cellects 0.2.7__py3-none-any.whl → 0.3.1__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.
@@ -1,24 +1,19 @@
1
1
  #!/usr/bin/env python3
2
- """Module containing classes for image processing and saving selected color space combinations.
2
+ """Module implementing an image processing pipeline for segmentation and analysis.
3
3
 
4
- This module provides two thread-based components for analyzing images and storing results:
5
-
6
- ProcessFirstImage handles initial segmentation, thresholding, clustering, and shape validation
7
- SaveCombinationThread stores processed features in parent objects asynchronously
8
- The processing pipeline includes Otsu thresholding, k-means clustering, connected component analysis,
9
- and geometric filtering based on size/shape constraints.
4
+ This module defines functionality to process images using various color space
5
+ combinations, filters, and segmentation techniques like K-means clustering or
6
+ Otsu thresholding. It supports logical operations between images and iterative refinement of
7
+ color space combinations by adding/removing channels based on validation criteria.
8
+ The pipeline evaluates resulting binary masks for blob statistics and spatial relationships.
10
9
 
11
10
  Classes
12
- ProcessFirstImage : Processes image data with segmentation techniques and validates shapes.
13
- SaveCombinationThread : Thread to save combination results while maintaining UI responsiveness.
14
-
15
- Functions (in ProcessFirstImage)
16
- shape_selection : Filters shapes by size thresholds and geometric criteria.
17
- kmeans : Performs clustering-based image segmentation into specified number of clusters.
18
- process_binary_image : Validates detected shapes against area constraints and spot count targets.
11
+ ProcessImage : Processes an image according to parameterized instructions, performing color space combination,
12
+ filtering, segmentation, and shape validation.
19
13
 
20
14
  Notes
21
- Uses threading.Thread for background operations to maintain application responsiveness during processing.
15
+ Relies on external functions from cellects.image_analysis module for core operations like
16
+ color space combination, filtering, PCA extraction, and segmentation.
22
17
  """
23
18
  import threading
24
19
  import logging
@@ -26,145 +21,299 @@ import numpy as np
26
21
  import cv2
27
22
  from numpy.typing import NDArray
28
23
  from typing import Tuple
29
- from cellects.image_analysis.image_segmentation import otsu_thresholding, combine_color_spaces
24
+ from numba.typed import Dict, List
25
+ import pandas as pd
26
+ from cellects.image_analysis.image_segmentation import combine_color_spaces, apply_filter, kmeans, extract_first_pc, otsu_thresholding
30
27
  from cellects.image_analysis.morphological_operations import shape_selection
31
28
 
32
29
 
33
- class ProcessFirstImage:
30
+ class ProcessImage:
34
31
  """
35
- A class for processing lists.
32
+ A class for processing an image according to a list of parameters.
36
33
  """
37
34
  def __init__(self, l):
38
35
  """
39
36
  Arguments:
40
37
  list : list
41
-
42
38
  """
39
+ self.stats = None
40
+ self.greyscale = None
43
41
  self.start_processing(l)
44
42
 
45
43
  def start_processing(self, l: list):
46
44
  """
45
+ Begin processing tasks based on the given process type.
47
46
 
48
- Start the processing based on given list input.
49
-
50
- The method processes the provided list to perform various operations
51
- on the image data. It sets up several attributes and performs different
52
- image processing tasks like Otsu thresholding or k-means clustering.
47
+ Parameters
48
+ ----------
49
+ l : list
50
+ A list containing parameters and instructions for processing.
51
+ Expected structure:
52
+ - First element: self.parent (object)
53
+ - Second element: params (dict)
54
+ - Third element: process type (str) ('one', 'PCA', 'add', 'subtract', or 'logical')
55
+ - Fourth element (if applicable): additional parameters based on process type.
53
56
 
54
- The method does not return any value.
57
+ Notes
58
+ -----
59
+ This function modifies instance attributes directly and performs various operations based on the `process` type.
55
60
  """
56
61
  self.parent = l[0]
57
- get_one_channel_result = l[1]
58
- combine_channels = l[2]
62
+ self.fact = pd.DataFrame(np.zeros((1, len(self.parent.factors)), dtype=np.uint32), columns=self.parent.factors)
63
+ self.params = l[1]
64
+ process = l[2]
59
65
  self.all_c_spaces = self.parent.all_c_spaces
60
- self.several_blob_per_arena = l[4]
61
- self.sample_number = l[5]
62
- self.horizontal_size = l[6]
63
- self.spot_shape = l[7]
64
- kmeans_clust_nb = l[8]
65
- self.biomask = l[9]
66
- self.backmask = l[10]
67
- if get_one_channel_result:
66
+ if process == 'one':
68
67
  self.csc_dict = l[3]
69
- self.image = combine_color_spaces(self.csc_dict, self.all_c_spaces)
70
- if kmeans_clust_nb is None:
71
- self.binary_image = otsu_thresholding(self.image)
72
- else:
73
- self.kmeans(kmeans_clust_nb, self.biomask, self.backmask)
74
- # self.parent.image = self.image
75
- # self.parent.kmeans(kmeans_clust_nb, self.biomask, self.backmask)
76
- # self.binary_image = self.parent.binary_image
77
- self.unaltered_concomp_nb, shapes = cv2.connectedComponents(self.binary_image)
78
- if 1 < self.unaltered_concomp_nb < 10000:
79
- self.total_area = np.sum(self.binary_image)
80
- inf_lim = np.min((100, np.ceil(self.binary_image.size / 1000)))
81
- if inf_lim < self.total_area < self.binary_image.size * 0.9:
82
- self.process_binary_image()
83
- self.parent.save_combination_features(self)
84
- # except RuntimeWarning:
85
- # Make sure that scaling and spot size are correct
86
- if combine_channels:
87
- i = l[3]
88
- possibilities = l[11]
89
- saved_color_space_list = self.parent.saved_color_space_list
90
- combination_features = self.parent.combination_features
91
- self.csc_dict = saved_color_space_list[i]
92
- previous_shape_number = combination_features[i, 4]
93
- previous_sum = combination_features[i, 5]
94
- for j in possibilities[::-1]:
95
- csc_dict2 = saved_color_space_list[j]
96
- csc_dict = self.csc_dict.copy()
97
- keys = list(csc_dict.keys())
98
-
99
- k2 = list(csc_dict2.keys())[0]
100
- v2 = csc_dict2[k2]
101
- if np.isin(k2, keys) and np.sum(v2 * csc_dict[k2]) != 0:
102
- break
103
- for factor in [2, 1]:
104
- if np.isin(k2, keys):
105
- csc_dict[k2] += v2 * factor
106
- else:
107
- csc_dict[k2] = v2 * factor
108
- self.image = combine_color_spaces(csc_dict, self.all_c_spaces)
109
- if kmeans_clust_nb is None:
110
- self.binary_image = otsu_thresholding(self.image)
111
- else:
112
- self.kmeans(kmeans_clust_nb, self.biomask, self.backmask)
113
- self.process_binary_image()
114
- self.total_area = self.validated_shapes.sum()
115
- if previous_shape_number >= self.shape_number and self.total_area > previous_sum * 0.9:
116
- previous_shape_number = self.shape_number
117
- previous_sum = self.total_area
118
- self.csc_dict = csc_dict.copy()
119
- self.unaltered_concomp_nb = combination_features[i, 3]
120
- self.parent.save_combination_features(self)
121
-
122
- def kmeans(self, cluster_number: int, biomask: NDArray[np.uint8]=None, backmask: NDArray[np.uint8]=None, bio_label=None):
123
- """
124
-
125
- Perform k-means clustering on the image to segment it into a specified number of clusters.
126
-
127
- Args:
128
- cluster_number (int): The desired number of clusters.
129
- biomask (NDArray[np.uint8]): Optional mask for biological regions. Default is None.
130
- backmask (NDArray[np.uint8]): Optional mask for background regions. Default is None.
131
- bio_label (int): The label assigned to the biological region. Default is None.
132
-
133
- Returns:
134
- None
135
-
136
- Note:
137
- This method modifies the `binary_image` and `bio_label` attributes of the instance.
138
-
139
- """
140
- image = self.image.reshape((-1, 1))
141
- image = np.float32(image)
142
- criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
143
- compactness, label, center = cv2.kmeans(image, cluster_number, None, criteria, attempts=10, flags=cv2.KMEANS_RANDOM_CENTERS)
144
- kmeans_image = np.uint8(label.flatten().reshape(self.image.shape[:2]))
145
- sum_per_label = np.zeros(cluster_number)
146
- self.binary_image = np.zeros(self.image.shape[:2], np.uint8)
147
- if bio_label is not None:
148
- self.binary_image[np.nonzero(kmeans_image == bio_label)] = 1
149
- self.bio_label = bio_label
68
+ self.combine_and_segment()
69
+ self.evaluate_segmentation()
70
+ elif process == 'PCA':
71
+ self.pca_and_segment()
72
+ self.evaluate_segmentation()
73
+ elif process == 'add':
74
+ self.try_adding_channels(l[3])
75
+ elif process == 'subtract':
76
+ self.try_subtracting_channels()
77
+ elif process == 'logical':
78
+ self.operation = l[3]
79
+ self.apply_logical_operation()
80
+
81
+ def combine_and_segment(self, csc_dict: Dict=None):
82
+ """
83
+ Combines color spaces and segments images into binary masks using either K-means clustering or Otsu's thresholding based on specified parameters.
84
+
85
+ Parameters
86
+ ----------
87
+ csc_dict : dict or None
88
+ Optional dictionary mapping color space abbreviations (e.g., 'bgr', 'hsv') to their relative contribution coefficients for combination. If not provided, uses the instance's `self.csc_dict` attribute instead.
89
+
90
+ """
91
+ if csc_dict is None:
92
+ csc_dict = self.csc_dict
93
+ self.image = combine_color_spaces(csc_dict, self.all_c_spaces)
94
+ self.apply_filter_and_segment()
95
+
96
+ def pca_and_segment(self):
97
+ """
98
+ Extract the first principal component and perform segmentation.
99
+
100
+ This method extracts the first principal component from the 'bgr' color space
101
+ and performs k-means clustering or Otsu thresholding to segment the image based on the
102
+ parameters provided.
103
+ """
104
+ self.image, _, first_pc_vector = extract_first_pc(self.all_c_spaces['bgr'])
105
+ self.csc_dict = Dict()
106
+ self.csc_dict['bgr'] = first_pc_vector
107
+ self.apply_filter_and_segment()
108
+
109
+ def apply_filter_and_segment(self):
110
+ self.greyscale = self.image
111
+ if self.params['filter_spec'] is not None and self.params['filter_spec']["filter1_type"] != "":
112
+ self.greyscale = apply_filter(self.greyscale, self.params['filter_spec']["filter1_type"], self.params['filter_spec']["filter1_param"])
113
+
114
+
115
+ if self.params['kmeans_clust_nb'] is not None and (self.params['bio_mask'] is not None or self.params['back_mask'] is not None):
116
+ self.binary_image, _, self.bio_label, _ = kmeans(self.greyscale, None, self.params['kmeans_clust_nb'],
117
+ self.params['bio_mask'], self.params['back_mask'])
118
+ else:
119
+ self.binary_image = otsu_thresholding(self.greyscale)
120
+ self.validated_shapes = self.binary_image
121
+
122
+ def evaluate_segmentation(self):
123
+ """
124
+ Use the filtering algorithm based on the kind of image to analyse
125
+ """
126
+ if self.params['is_first_image']:
127
+ self.eval_first_image()
150
128
  else:
151
- if biomask is not None:
152
- all_labels = kmeans_image[biomask[0], biomask[1]]
153
- for i in range(cluster_number):
154
- sum_per_label[i] = (all_labels == i).sum()
155
- self.bio_label = np.nonzero(sum_per_label == np.max(sum_per_label))
156
- elif backmask is not None:
157
- all_labels = kmeans_image[backmask[0], backmask[1]]
158
- for i in range(cluster_number):
159
- sum_per_label[i] = (all_labels == i).sum()
160
- self.bio_label = np.nonzero(sum_per_label == np.min(sum_per_label))
129
+ self.eval_any_image()
130
+
131
+ def eval_first_image(self):
132
+ """
133
+ First image filtering process for binary images.
134
+
135
+ This method processes the first binary image by identifying connected components, computing
136
+ the total area of the image and its potential size limits. If the number of blobs and their
137
+ total area fall within acceptable thresholds, it proceeds with additional processing and saving.
138
+ """
139
+ self.fact['unaltered_blob_nb'], shapes = cv2.connectedComponents(self.binary_image)
140
+ self.fact['unaltered_blob_nb'] -= 1
141
+ if 1 <= self.fact['unaltered_blob_nb'].values[0] < 10000:
142
+ self.fact['total_area'] = np.sum(self.binary_image)
143
+ inf_lim = np.min((20, np.ceil(self.binary_image.size / 1000)))
144
+ if inf_lim < self.fact['total_area'].values[0] < self.binary_image.size * 0.9:
145
+ self.process_first_binary_image()
146
+ self.save_combination()
147
+
148
+ def eval_any_image(self):
149
+ """
150
+
151
+ Summarizes the binary image analysis and determines blob characteristics.
152
+
153
+ Evaluates a binary image to determine various attributes like surface area,
154
+ blob number, and their relative positions within specified masks. It also
155
+ checks for common areas with a reference image and saves the combination if
156
+ certain conditions are met.
157
+ """
158
+ surf = self.binary_image.sum()
159
+ if surf < self.params['total_surface_area']:
160
+ self.fact['unaltered_blob_nb'], shapes = cv2.connectedComponents(self.binary_image)
161
+ self.fact['unaltered_blob_nb'] -= 1
162
+ test: bool = True
163
+ if self.params['arenas_mask'] is not None:
164
+ self.fact['out_of_arenas'] = np.sum(self.binary_image * self.params['out_of_arenas_mask'])
165
+ self.fact['in_arenas'] = np.sum(self.binary_image * self.params['arenas_mask'])
166
+ test = self.fact['out_of_arenas'].values[0] < self.fact['in_arenas'].values[0]
167
+ if test:
168
+ if self.params['con_comp_extent'][0] <= self.fact['unaltered_blob_nb'].values[0] <= self.params['con_comp_extent'][1]:
169
+ if self.params['ref_image'] is not None:
170
+ self.fact['common_with_ref'] = np.sum(self.params['ref_image'] * self.binary_image)
171
+ test = self.fact['common_with_ref'].values[0] > 0
172
+ if test:
173
+ self.fact['blob_nb'], shapes, self.stats, centroids = cv2.connectedComponentsWithStats(self.binary_image)
174
+ self.fact['blob_nb'] -= 1
175
+ if np.all(np.sort(self.stats[:, 4])[:-1] < self.params['max_blob_size']):
176
+ self.save_combination()
177
+
178
+ def apply_logical_operation(self):
179
+ """
180
+ Apply a logical operation between two saved images.
181
+
182
+ This method applies a specified logical operation ('And' or 'Or')
183
+ between two images stored in the parent's saved_images_list. The result
184
+ is stored as a binary image and validated, with color space information
185
+ updated accordingly.
186
+
187
+ Notes
188
+ -----
189
+ This method modifies the following instance attributes:
190
+ - `binary_image`
191
+ - `validated_shapes`
192
+ - `image`
193
+ - `csc_dict`
194
+ """
195
+ im1 = self.parent.saved_images_list[self.operation[0]]
196
+ im2 = self.parent.saved_images_list[self.operation[1]]
197
+ if self.operation['logical'] == 'And':
198
+ self.binary_image = np.logical_and(im1, im2).astype(np.uint8)
199
+ elif self.operation['logical'] == 'Or':
200
+ self.binary_image = np.logical_or(im1, im2).astype(np.uint8)
201
+ self.validated_shapes = self.binary_image
202
+ self.greyscale = self.parent.converted_images_list[self.operation[0]]
203
+ csc1 = self.parent.saved_color_space_list[self.operation[0]]
204
+ csc2 = self.parent.saved_color_space_list[self.operation[1]]
205
+ self.csc_dict = {}
206
+ for k, v in csc1.items():
207
+ self.csc_dict[k] = v
208
+ for k, v in csc2.items():
209
+ self.csc_dict[k] = v
210
+ self.csc_dict['logical'] = self.operation['logical']
211
+ self.evaluate_segmentation()
212
+
213
+ def try_adding_channels(self, i: int):
214
+ """
215
+ Try adding channels to the current color space combination.
216
+
217
+ Extend the functionality of a selected color space combination by attempting
218
+ to add channels from other combinations, evaluating the results based on
219
+ the number of shapes and total area.
220
+
221
+ Parameters
222
+ ----------
223
+ i : int
224
+ The index of the saved color space and combination features to start with.
225
+ """
226
+ saved_color_space_list = self.parent.saved_color_space_list
227
+ combination_features = self.parent.combination_features
228
+ self.csc_dict = saved_color_space_list[i]
229
+ previous_shape_number = combination_features.loc[i, 'blob_nb']
230
+ previous_sum = combination_features.loc[i, 'total_area']
231
+ for j in self.params['possibilities'][::-1]:
232
+ csc_dict2 = saved_color_space_list[j]
233
+ csc_dict = self.csc_dict.copy()
234
+ keys = list(csc_dict.keys())
235
+
236
+ k2 = list(csc_dict2.keys())[0]
237
+ v2 = csc_dict2[k2]
238
+ if np.isin(k2, keys) and np.sum(v2 * csc_dict[k2]) != 0:
239
+ break
240
+ for factor in [2, 1]:
241
+ if np.isin(k2, keys):
242
+ csc_dict[k2] += v2 * factor
243
+ else:
244
+ csc_dict[k2] = v2 * factor
245
+ self.combine_and_segment(csc_dict)
246
+ if self.params['is_first_image']:
247
+ self.process_first_binary_image()
248
+ else:
249
+ self.fact['blob_nb'], shapes, self.stats, centroids = cv2.connectedComponentsWithStats(self.validated_shapes)
250
+ self.fact['blob_nb'] -= 1
251
+ self.fact['total_area'] = self.validated_shapes.sum()
252
+ if self.fact['blob_nb'].values[0] < previous_shape_number and self.fact['total_area'].values[0] > previous_sum * 0.9:
253
+ previous_shape_number = self.fact['blob_nb'].values[0]
254
+ previous_sum = self.fact['total_area'].values[0]
255
+ self.csc_dict = csc_dict.copy()
256
+ self.fact['unaltered_blob_nb'] = combination_features.loc[i, 'unaltered_blob_nb']
257
+ self.save_combination()
258
+
259
+ def try_subtracting_channels(self):
260
+ """
261
+ Tries to subtract channels to find the optimal color space combination.
262
+
263
+ This method attempts to remove color spaces one by one from the image
264
+ to find a combination that maintains the majority of areas while reducing
265
+ the number of color spaces. This process is repeated until no further
266
+ improvements are possible.
267
+ """
268
+ potentials = self.parent.all_combined
269
+ # Try to remove color space one by one
270
+ i = 0
271
+ original_length = len(potentials)
272
+ # The while loop until one col space remains or the removal of one implies a strong enough area change
273
+ while np.logical_and(len(potentials) > 1, i < original_length - 1):
274
+ self.combine_and_segment(potentials)
275
+ if self.params['is_first_image']:
276
+ self.process_first_binary_image()
277
+ previous_blob_nb = self.fact['blob_nb'].values[0]
161
278
  else:
162
- for i in range(cluster_number):
163
- sum_per_label[i] = (kmeans_image == i).sum()
164
- self.bio_label = np.nonzero(sum_per_label == np.min(sum_per_label))
165
- self.binary_image[np.nonzero(kmeans_image == self.bio_label)] = 1
279
+ previous_blob_nb, shapes, self.stats, centroids = cv2.connectedComponentsWithStats(
280
+ self.validated_shapes)
281
+ previous_blob_nb -= 1
282
+ previous_sum = self.validated_shapes.sum()
283
+ color_space_to_remove = List()
284
+ previous_c_space = list(potentials.keys())[-1]
285
+ for c_space in potentials.keys():
286
+ try_potentials = potentials.copy()
287
+ try_potentials.pop(c_space)
288
+ if i > 0:
289
+ try_potentials.pop(previous_c_space)
290
+ self.combine_and_segment(try_potentials)
291
+ if self.params['is_first_image']:
292
+ self.process_first_binary_image()
293
+ else:
294
+ self.fact['blob_nb'], shapes, self.stats, centroids = cv2.connectedComponentsWithStats(
295
+ self.validated_shapes)
296
+ self.fact['blob_nb'] -= 1
297
+ self.fact['total_area'] = self.validated_shapes.sum()
298
+ if self.fact['blob_nb'].values[0] < previous_blob_nb and self.fact['total_area'].values[0] > previous_sum * 0.9:
299
+ previous_blob_nb = self.fact['blob_nb'].values[0]
300
+ previous_sum = self.fact['total_area'].values[0]
301
+ self.csc_dict = try_potentials.copy()
302
+ self.fact['unaltered_blob_nb'] = previous_blob_nb
303
+ self.save_combination()
304
+ # If removing that color space helps, we remove it from potentials
305
+ color_space_to_remove.append(c_space)
306
+ if i > 0:
307
+ color_space_to_remove.append(previous_c_space)
308
+ previous_c_space = c_space
309
+ if len(color_space_to_remove) == 0:
310
+ break
311
+ color_space_to_remove = np.unique(color_space_to_remove)
312
+ for remove_col_space in color_space_to_remove:
313
+ potentials.pop(remove_col_space)
314
+ i += 1
166
315
 
167
- def process_binary_image(self):
316
+ def process_first_binary_image(self):
168
317
  """
169
318
  Process the binary image to identify and validate shapes.
170
319
 
@@ -174,57 +323,38 @@ class ProcessFirstImage:
174
323
  sample number or applies additional filtering if necessary.
175
324
 
176
325
  """
177
- shapes_features = shape_selection(self.binary_image, true_shape_number=self.sample_number, horizontal_size=self.horizontal_size,
178
- spot_shape=self.spot_shape, several_blob_per_arena=self.several_blob_per_arena,
179
- bio_mask=self.biomask, back_mask=self.backmask)
180
- self.validated_shapes, self.shape_number, self.stats, self.centroids = shapes_features
181
-
326
+ shapes_features = shape_selection(self.binary_image, true_shape_number=self.params['blob_nb'],
327
+ horizontal_size=self.params['blob_size'], spot_shape=self.params['blob_shape'],
328
+ several_blob_per_arena=self.params['several_blob_per_arena'],
329
+ bio_mask=self.params['bio_mask'], back_mask=self.params['back_mask'])
330
+ self.validated_shapes, self.fact['blob_nb'], self.stats, self.centroids = shapes_features
182
331
 
183
- class SaveCombinationThread(threading.Thread):
184
- """
185
- SaveCombinationThread
332
+ def save_combination(self):
333
+ """
334
+ Saves the calculated features and masks for a combination of shapes.
186
335
 
187
- This class represents a thread for saving combinations.
336
+ This method calculates various statistical properties (std) and sums for the
337
+ validated shapes, and optionally computes sums for bio and back masks if they are
338
+ specified in the parameters.
188
339
 
189
- """
190
- def __init__(self, parent=None):
191
- """
192
- **Args:**
193
-
194
- - `parent`: The parent object that initiated the thread. This is an optional argument and defaults to 'None'.
195
-
196
- """
197
- # super(SaveCombinationThread, self).__init__()
198
- threading.Thread.__init__(self)
199
- self.parent = parent
200
-
201
- def run(self):
202
- """
203
- Runs the color space combination process and saves the results.
204
-
205
- This method performs several tasks to save intermediate and final
206
- results of the color space combination process. It logs messages,
207
- updates lists with valid shapes, converts images to a specific format,
208
- and updates combination features with various statistics. The method
209
- also handles biomask and backmask calculations if they are not None.
210
- Finally, it increments the saved color space number counter.
211
- """
212
- logging.info(f"Saving results from the color space combination: {self.process_i.csc_dict}. {self.process_i.shape_number} distinct specimen(s) detected.")
213
- self.parent.saved_images_list.append(self.process_i.validated_shapes)
214
- self.parent.converted_images_list.append(np.round(self.process_i.image).astype(np.uint8))
215
- self.parent.saved_color_space_list.append(self.process_i.csc_dict)
216
- self.parent.combination_features[self.parent.saved_csc_nb, :3] = list(self.process_i.csc_dict.values())[0]
217
- self.parent.combination_features[self.parent.saved_csc_nb, 3] = self.process_i.unaltered_concomp_nb - 1 # unaltered_cc_nb
218
- self.parent.combination_features[self.parent.saved_csc_nb, 4] = self.process_i.shape_number # cc_nb
219
- self.parent.combination_features[self.parent.saved_csc_nb, 5] = self.process_i.total_area # area
220
- self.parent.combination_features[self.parent.saved_csc_nb, 6] = np.std(self.process_i.stats[1:, 2]) # width_std
221
- self.parent.combination_features[self.parent.saved_csc_nb, 7] = np.std(self.process_i.stats[1:, 3]) # height_std
222
- self.parent.combination_features[self.parent.saved_csc_nb, 8] = np.std(self.process_i.stats[1:, 4]) # area_std
223
- if self.process_i.biomask is not None:
224
- self.parent.combination_features[self.parent.saved_csc_nb, 9] = np.sum(
225
- self.process_i.validated_shapes[self.process_i.biomask[0], self.process_i.biomask[1]])
226
- if self.process_i.backmask is not None:
227
- self.parent.combination_features[self.parent.saved_csc_nb, 10] = np.sum(
228
- (1 - self.process_i.validated_shapes)[self.process_i.backmask[0], self.process_i.backmask[1]])
229
- self.parent.saved_csc_nb += 1
230
- logging.info("end")
340
+ Parameters
341
+ ----------
342
+ self : object
343
+ The instance of the class containing this method. Must have attributes:
344
+ - ``validated_shapes``: (ndarray) Array of validated shapes.
345
+ - ``stats``: (ndarray) Statistics array containing width, height, and area.
346
+ - ``params``: dictionary with parameters including 'bio_mask' and 'back_mask'.
347
+ - ``fact``: dictionary to store the calculated features.
348
+ - ``parent``: The parent object containing the method `save_combination_features`.
349
+ """
350
+ self.fact['total_area'] = self.validated_shapes.sum()
351
+ self.fact['width_std'] = np.std(self.stats[1:, 2])
352
+ self.fact['height_std'] = np.std(self.stats[1:, 3])
353
+ self.fact['area_std'] = np.std(self.stats[1:, 4])
354
+ if self.params['bio_mask'] is not None:
355
+ self.fact['bio_sum'] = self.validated_shapes[self.params['bio_mask'][0], self.params['bio_mask'][1]].sum()
356
+ if self.params['back_mask'] is not None:
357
+ self.fact['back_sum'] = (1 - self.validated_shapes)[self.params['back_mask'][0], self.params['back_mask'][1]].sum()
358
+ self.parent.save_combination_features(self)
359
+
360
+