simba-uw-tf-dev 4.6.2__py3-none-any.whl → 4.7.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.
- simba/assets/.recent_projects.txt +1 -0
- simba/assets/lookups/tooptips.json +6 -1
- simba/assets/lookups/yolo_schematics/yolo_mitra.csv +9 -0
- simba/data_processors/agg_clf_counter_mp.py +52 -53
- simba/data_processors/blob_location_computer.py +1 -1
- simba/data_processors/circling_detector.py +30 -13
- simba/data_processors/cuda/geometry.py +45 -27
- simba/data_processors/cuda/image.py +1648 -1598
- simba/data_processors/cuda/statistics.py +72 -26
- simba/data_processors/cuda/timeseries.py +1 -1
- simba/data_processors/cue_light_analyzer.py +5 -9
- simba/data_processors/egocentric_aligner.py +25 -7
- simba/data_processors/freezing_detector.py +55 -47
- simba/data_processors/kleinberg_calculator.py +61 -29
- simba/feature_extractors/feature_subsets.py +14 -7
- simba/feature_extractors/mitra_feature_extractor.py +2 -2
- simba/feature_extractors/straub_tail_analyzer.py +4 -6
- simba/labelling/standard_labeller.py +1 -1
- simba/mixins/config_reader.py +5 -2
- simba/mixins/geometry_mixin.py +22 -36
- simba/mixins/image_mixin.py +24 -28
- simba/mixins/plotting_mixin.py +28 -10
- simba/mixins/statistics_mixin.py +48 -11
- simba/mixins/timeseries_features_mixin.py +1 -1
- simba/mixins/train_model_mixin.py +68 -33
- simba/model/inference_batch.py +2 -2
- simba/model/yolo_seg_inference.py +3 -3
- simba/outlier_tools/skip_outlier_correction.py +1 -1
- simba/plotting/ROI_feature_visualizer_mp.py +3 -5
- simba/plotting/clf_validator_mp.py +4 -5
- simba/plotting/cue_light_visualizer.py +6 -7
- simba/plotting/directing_animals_visualizer_mp.py +2 -3
- simba/plotting/distance_plotter_mp.py +378 -378
- simba/plotting/gantt_creator.py +29 -10
- simba/plotting/gantt_creator_mp.py +96 -33
- simba/plotting/geometry_plotter.py +270 -272
- simba/plotting/heat_mapper_clf_mp.py +4 -6
- simba/plotting/heat_mapper_location_mp.py +2 -2
- simba/plotting/light_dark_box_plotter.py +2 -2
- simba/plotting/path_plotter_mp.py +26 -29
- simba/plotting/plot_clf_results_mp.py +455 -454
- simba/plotting/pose_plotter_mp.py +28 -29
- simba/plotting/probability_plot_creator_mp.py +288 -288
- simba/plotting/roi_plotter_mp.py +31 -31
- simba/plotting/single_run_model_validation_video_mp.py +427 -427
- simba/plotting/spontaneous_alternation_plotter.py +2 -3
- simba/plotting/yolo_pose_track_visualizer.py +32 -27
- simba/plotting/yolo_pose_visualizer.py +35 -36
- simba/plotting/yolo_seg_visualizer.py +2 -3
- simba/pose_importers/simba_blob_importer.py +3 -3
- simba/roi_tools/roi_aggregate_stats_mp.py +5 -4
- simba/roi_tools/roi_clf_calculator_mp.py +4 -4
- simba/sandbox/analyze_runtimes.py +30 -0
- simba/sandbox/cuda/egocentric_rotator.py +374 -374
- simba/sandbox/get_cpu_pool.py +5 -0
- simba/sandbox/proboscis_to_tip.py +28 -0
- simba/sandbox/test_directionality.py +47 -0
- simba/sandbox/test_nonstatic_directionality.py +27 -0
- simba/sandbox/test_pycharm_cuda.py +51 -0
- simba/sandbox/test_simba_install.py +41 -0
- simba/sandbox/test_static_directionality.py +26 -0
- simba/sandbox/test_static_directionality_2d.py +26 -0
- simba/sandbox/verify_env.py +42 -0
- simba/third_party_label_appenders/transform/coco_keypoints_to_yolo.py +3 -3
- simba/third_party_label_appenders/transform/coco_keypoints_to_yolo_bbox.py +2 -2
- simba/third_party_label_appenders/transform/simba_to_yolo.py +8 -5
- simba/ui/pop_ups/clf_plot_pop_up.py +2 -2
- simba/ui/pop_ups/fsttc_pop_up.py +27 -25
- simba/ui/pop_ups/gantt_pop_up.py +31 -6
- simba/ui/pop_ups/kleinberg_pop_up.py +39 -40
- simba/ui/pop_ups/run_machine_models_popup.py +21 -21
- simba/ui/pop_ups/simba_to_yolo_keypoints_popup.py +2 -2
- simba/ui/pop_ups/video_processing_pop_up.py +37 -29
- simba/ui/pop_ups/yolo_inference_popup.py +1 -1
- simba/ui/pop_ups/yolo_pose_train_popup.py +1 -1
- simba/ui/tkinter_functions.py +3 -0
- simba/utils/custom_feature_extractor.py +1 -1
- simba/utils/data.py +90 -14
- simba/utils/enums.py +1 -0
- simba/utils/errors.py +441 -440
- simba/utils/lookups.py +1203 -1203
- simba/utils/printing.py +124 -124
- simba/utils/read_write.py +3769 -3721
- simba/utils/yolo.py +10 -1
- simba/video_processors/blob_tracking_executor.py +2 -2
- simba/video_processors/clahe_ui.py +1 -1
- simba/video_processors/egocentric_video_rotator.py +44 -41
- simba/video_processors/multi_cropper.py +1 -1
- simba/video_processors/video_processing.py +75 -33
- simba/video_processors/videos_to_frames.py +43 -33
- {simba_uw_tf_dev-4.6.2.dist-info → simba_uw_tf_dev-4.7.2.dist-info}/METADATA +4 -3
- {simba_uw_tf_dev-4.6.2.dist-info → simba_uw_tf_dev-4.7.2.dist-info}/RECORD +96 -85
- {simba_uw_tf_dev-4.6.2.dist-info → simba_uw_tf_dev-4.7.2.dist-info}/LICENSE +0 -0
- {simba_uw_tf_dev-4.6.2.dist-info → simba_uw_tf_dev-4.7.2.dist-info}/WHEEL +0 -0
- {simba_uw_tf_dev-4.6.2.dist-info → simba_uw_tf_dev-4.7.2.dist-info}/entry_points.txt +0 -0
- {simba_uw_tf_dev-4.6.2.dist-info → simba_uw_tf_dev-4.7.2.dist-info}/top_level.txt +0 -0
|
@@ -1,378 +1,378 @@
|
|
|
1
|
-
__author__ = "Simon Nilsson; sronilsson@gmail.com"
|
|
2
|
-
import functools
|
|
3
|
-
import multiprocessing
|
|
4
|
-
import os
|
|
5
|
-
import platform
|
|
6
|
-
from typing import Dict, List, Optional, Union
|
|
7
|
-
|
|
8
|
-
import cv2
|
|
9
|
-
import numpy as np
|
|
10
|
-
from numba import jit
|
|
11
|
-
|
|
12
|
-
from simba.mixins.config_reader import ConfigReader
|
|
13
|
-
from simba.mixins.feature_extraction_mixin import FeatureExtractionMixin
|
|
14
|
-
from simba.mixins.plotting_mixin import PlottingMixin
|
|
15
|
-
from simba.utils.checks import (
|
|
16
|
-
check_all_file_names_are_represented_in_video_log,
|
|
17
|
-
check_file_exist_and_readable, check_instance, check_int, check_valid_lst)
|
|
18
|
-
from simba.utils.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
from simba.utils.
|
|
22
|
-
from simba.utils.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
line_data =
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
:param
|
|
91
|
-
:param bool
|
|
92
|
-
:param bool
|
|
93
|
-
:param
|
|
94
|
-
:param
|
|
95
|
-
:param
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
:
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
:
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
>>>
|
|
111
|
-
>>>
|
|
112
|
-
>>> distance_plotter.
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
(
|
|
157
|
-
|
|
158
|
-
self.
|
|
159
|
-
self.
|
|
160
|
-
self.
|
|
161
|
-
self.
|
|
162
|
-
self.
|
|
163
|
-
self.
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
@
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
self.
|
|
206
|
-
self.
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
frm_range = np.
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
distances =
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
pool
|
|
307
|
-
if self.video_setting:
|
|
308
|
-
concatenate_videos_in_folder(
|
|
309
|
-
in_folder=self.temp_folder,
|
|
310
|
-
save_path=self.save_video_path,
|
|
311
|
-
video_format="avi",
|
|
312
|
-
)
|
|
313
|
-
video_timer.stop_timer()
|
|
314
|
-
stdout_success(
|
|
315
|
-
msg=f"Distance visualizations created for {video_name} saved at {self.line_plot_dir}",
|
|
316
|
-
elapsed_time=video_timer.elapsed_time_str,
|
|
317
|
-
)
|
|
318
|
-
self.timer.stop_timer()
|
|
319
|
-
stdout_success(
|
|
320
|
-
msg=f"Distance visualizations complete for {len(self.data_paths)} video(s)",
|
|
321
|
-
elapsed_time=self.timer.elapsed_time_str,
|
|
322
|
-
)
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
# style_attr = {'width': 640, 'height': 480, 'line width': 6, 'font size': 12, 'y_max': -1, 'opacity': 0.5}
|
|
326
|
-
# line_attr = [['Center_1', 'Center_2', 'Green'], ['Ear_left_2', 'Ear_right_2', 'Red']]
|
|
327
|
-
# test = DistancePlotterMultiCore(config_path=r'/Users/simon/Desktop/envs/simba/troubleshooting/two_black_animals_14bp/project_folder/project_config.ini',
|
|
328
|
-
# frame_setting=True,
|
|
329
|
-
# video_setting=True,
|
|
330
|
-
# style_attr=style_attr,
|
|
331
|
-
# final_img=True,
|
|
332
|
-
# data_paths=['/Users/simon/Desktop/envs/simba/troubleshooting/two_black_animals_14bp/project_folder/csv/outlier_corrected_movement_location/Together_1.csv'],
|
|
333
|
-
# line_attr=line_attr,
|
|
334
|
-
# core_cnt=-1)
|
|
335
|
-
# test.run()
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
# style_attr = {'width': 640, 'height': 480, 'line width': 6, 'font size': 8, 'y_max': 'auto', 'opacity': 0.9}
|
|
339
|
-
# line_attr = {0: ['Center_1', 'Center_2', 'Green'], 1: ['Ear_left_2', 'Ear_left_1', 'Red']}
|
|
340
|
-
#
|
|
341
|
-
# test = DistancePlotterMultiCore(config_path=r'/Users/simon/Desktop/envs/troubleshooting/two_black_animals_14bp/project_folder/project_config.ini',
|
|
342
|
-
# frame_setting=False,
|
|
343
|
-
# video_setting=True,
|
|
344
|
-
# style_attr=style_attr,
|
|
345
|
-
# final_img=True,
|
|
346
|
-
# files_found=['/Users/simon/Desktop/envs/troubleshooting/two_black_animals_14bp/project_folder/csv/machine_results/Together_1.csv'],
|
|
347
|
-
# line_attr=line_attr,
|
|
348
|
-
# core_cnt=3)
|
|
349
|
-
# test.create_distance_plot()
|
|
350
|
-
# #
|
|
351
|
-
# style_attr = {'width': 640, 'height': 480, 'line width': 6, 'font size': 8}
|
|
352
|
-
# line_attr = {0: ['Termite_1_Head_1', 'Termite_1_Thorax_1', 'Dark-red']}
|
|
353
|
-
#
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
# style_attr = {'width': 640, 'height': 480, 'line width': 6, 'font size': 8, 'opacity': 0.5, 'y_max': 'auto'}
|
|
357
|
-
# line_attr = {0: ['Center_1', 'Center_2', 'Green'], 1: ['Ear_left_2', 'Ear_left_1', 'Red']}
|
|
358
|
-
#
|
|
359
|
-
# test = DistancePlotterMultiCore(config_path=r'/Users/simon/Desktop/envs/troubleshooting/two_black_animals_14bp/project_folder/project_config.ini',
|
|
360
|
-
# frame_setting=False,
|
|
361
|
-
# video_setting=True,
|
|
362
|
-
# style_attr=style_attr,
|
|
363
|
-
# final_img=False,
|
|
364
|
-
# files_found=['/Users/simon/Desktop/envs/troubleshooting/two_black_animals_14bp/project_folder/csv/machine_results/Together_1.csv'],
|
|
365
|
-
# line_attr=line_attr,
|
|
366
|
-
# core_cnt=5)
|
|
367
|
-
# test.create_distance_plot()
|
|
368
|
-
|
|
369
|
-
# style_attr = {'width': 640, 'height': 480, 'line width': 6, 'font size': 8}
|
|
370
|
-
# line_attr = {0: ['Termite_1_Head_1', 'Termite_1_Thorax_1', 'Dark-red']}
|
|
371
|
-
|
|
372
|
-
# test = DistancePlotterSingleCore(config_path=r'/Users/simon/Desktop/envs/troubleshooting/Termites_5/project_folder/project_config.ini',
|
|
373
|
-
# frame_setting=False,
|
|
374
|
-
# video_setting=True,
|
|
375
|
-
# style_attr=style_attr,
|
|
376
|
-
# files_found=['/Users/simon/Desktop/envs/troubleshooting/Termites_5/project_folder/csv/outlier_corrected_movement_location/termites_1.csv'],
|
|
377
|
-
# line_attr=line_attr)
|
|
378
|
-
# test.create_distance_plot()
|
|
1
|
+
__author__ = "Simon Nilsson; sronilsson@gmail.com"
|
|
2
|
+
import functools
|
|
3
|
+
import multiprocessing
|
|
4
|
+
import os
|
|
5
|
+
import platform
|
|
6
|
+
from typing import Dict, List, Optional, Union
|
|
7
|
+
|
|
8
|
+
import cv2
|
|
9
|
+
import numpy as np
|
|
10
|
+
from numba import jit
|
|
11
|
+
|
|
12
|
+
from simba.mixins.config_reader import ConfigReader
|
|
13
|
+
from simba.mixins.feature_extraction_mixin import FeatureExtractionMixin
|
|
14
|
+
from simba.mixins.plotting_mixin import PlottingMixin
|
|
15
|
+
from simba.utils.checks import (
|
|
16
|
+
check_all_file_names_are_represented_in_video_log,
|
|
17
|
+
check_file_exist_and_readable, check_instance, check_int, check_valid_lst)
|
|
18
|
+
from simba.utils.data import terminate_cpu_pool
|
|
19
|
+
from simba.utils.errors import (CountError, InvalidInputError,
|
|
20
|
+
NoSpecifiedOutputError)
|
|
21
|
+
from simba.utils.lookups import get_color_dict
|
|
22
|
+
from simba.utils.printing import SimbaTimer, stdout_success
|
|
23
|
+
from simba.utils.read_write import (concatenate_videos_in_folder,
|
|
24
|
+
find_core_cnt, get_fn_ext, read_df)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def distance_plotter_mp(
|
|
28
|
+
frm_cnts: np.array,
|
|
29
|
+
distances: np.ndarray,
|
|
30
|
+
colors: List[str],
|
|
31
|
+
video_setting: bool,
|
|
32
|
+
frame_setting: bool,
|
|
33
|
+
video_name: str,
|
|
34
|
+
video_save_dir: str,
|
|
35
|
+
frame_folder_dir: str,
|
|
36
|
+
style_attr: dict,
|
|
37
|
+
fps: int,
|
|
38
|
+
):
|
|
39
|
+
|
|
40
|
+
group = int(distances[frm_cnts[0], 0])
|
|
41
|
+
video_writer = None
|
|
42
|
+
if video_setting:
|
|
43
|
+
fourcc = cv2.VideoWriter_fourcc(*"DIVX")
|
|
44
|
+
temp_video_save_path = os.path.join(video_save_dir, f"{group}.avi")
|
|
45
|
+
video_writer = cv2.VideoWriter(
|
|
46
|
+
temp_video_save_path,
|
|
47
|
+
fourcc,
|
|
48
|
+
fps,
|
|
49
|
+
(style_attr["width"], style_attr["height"]),
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
for frm_cnt in frm_cnts:
|
|
53
|
+
line_data = distances[:frm_cnt, 1:]
|
|
54
|
+
line_data = np.hsplit(line_data, line_data.shape[1])
|
|
55
|
+
|
|
56
|
+
img = PlottingMixin.make_line_plot_plotly(
|
|
57
|
+
data=line_data,
|
|
58
|
+
colors=colors,
|
|
59
|
+
width=style_attr["width"],
|
|
60
|
+
height=style_attr["height"],
|
|
61
|
+
line_width=style_attr["line width"],
|
|
62
|
+
font_size=style_attr["font size"],
|
|
63
|
+
title="Animal distances",
|
|
64
|
+
y_lbl="distance (cm)",
|
|
65
|
+
x_lbl="frame count",
|
|
66
|
+
x_lbl_divisor=fps,
|
|
67
|
+
y_max=style_attr["y_max"],
|
|
68
|
+
line_opacity=style_attr["opacity"],
|
|
69
|
+
save_path=None,
|
|
70
|
+
).astype(np.uint8)
|
|
71
|
+
if video_setting:
|
|
72
|
+
video_writer.write(img[:, :, :3])
|
|
73
|
+
if frame_setting:
|
|
74
|
+
frm_name = os.path.join(frame_folder_dir, f"{frm_cnt}.png")
|
|
75
|
+
cv2.imwrite(frm_name, np.uint8(img))
|
|
76
|
+
print(
|
|
77
|
+
f"Distance frame created: {frm_cnt} (of {distances.shape[0]}), Video: {video_name}, Processing core: {group}"
|
|
78
|
+
)
|
|
79
|
+
if video_setting:
|
|
80
|
+
video_writer.release()
|
|
81
|
+
return group
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class DistancePlotterMultiCore(ConfigReader, PlottingMixin):
|
|
85
|
+
"""
|
|
86
|
+
Visualize the distances between pose-estimated body-parts (e.g., two animals) through line
|
|
87
|
+
charts. Results are saved as individual line charts, and/or a video of line charts.
|
|
88
|
+
Uses multiprocessing.
|
|
89
|
+
|
|
90
|
+
:param str config_path: path to SimBA project config file in Configparser format
|
|
91
|
+
:param bool frame_setting: If True, creates individual frames.
|
|
92
|
+
:param bool video_setting: If True, creates videos.
|
|
93
|
+
:param bool final_img: If True, creates a single .png representing the entire video.
|
|
94
|
+
:param dict style_attr: Video style attributes (font sizes, line opacity etc.)
|
|
95
|
+
:param List[Union[str, os.PathLike]] data_paths: Files to visualize.
|
|
96
|
+
:param dict line_attr: Representing the body-parts to visualize the distance between and their colors.
|
|
97
|
+
|
|
98
|
+
.. note::
|
|
99
|
+
`GitHub tutorial/documentation <https://github.com/sgoldenlab/simba/blob/master/docs/tutorial.md#step-11-visualizations>`__.
|
|
100
|
+
|
|
101
|
+
.. image:: _static/img/DistancePlotterMultiCore.png
|
|
102
|
+
:width: 600
|
|
103
|
+
:align: center
|
|
104
|
+
|
|
105
|
+
.. image:: _static/img/DistancePlotterMultiCore_1.gif
|
|
106
|
+
:width: 600
|
|
107
|
+
:align: center
|
|
108
|
+
|
|
109
|
+
:example:
|
|
110
|
+
>>> style_attr = {'width': 640, 'height': 480, 'line width': 6, 'font size': 8, 'opacity': 0.5}
|
|
111
|
+
>>> line_attr = {0: ['Center_1', 'Center_2', 'Green'], 1: ['Ear_left_2', 'Ear_left_1', 'Red']}
|
|
112
|
+
>>> distance_plotter = DistancePlotterMultiCore(config_path=r'/tests_/project_folder/project_config.ini', frame_setting=False, video_setting=True, final_img=True, style_attr=style_attr, line_attr=line_attr, files_found=['/test_/project_folder/csv/machine_results/Together_1.csv'], core_cnt=5)
|
|
113
|
+
>>> distance_plotter.run()
|
|
114
|
+
"""
|
|
115
|
+
|
|
116
|
+
def __init__(
|
|
117
|
+
self,
|
|
118
|
+
config_path: Union[str, os.PathLike],
|
|
119
|
+
data_paths: List[Union[str, os.PathLike]],
|
|
120
|
+
frame_setting: bool,
|
|
121
|
+
video_setting: bool,
|
|
122
|
+
final_img: bool,
|
|
123
|
+
style_attr: Dict[str, int],
|
|
124
|
+
line_attr: List[List[str]],
|
|
125
|
+
core_cnt: Optional[int] = -1,
|
|
126
|
+
):
|
|
127
|
+
|
|
128
|
+
if (not frame_setting) and (not video_setting) and (not final_img):
|
|
129
|
+
raise NoSpecifiedOutputError(
|
|
130
|
+
msg="Please choice to create frames and/or video distance plots",
|
|
131
|
+
source=self.__class__.__name__,
|
|
132
|
+
)
|
|
133
|
+
check_int(
|
|
134
|
+
name=f"{self.__class__.__name__} core_cnt",
|
|
135
|
+
value=core_cnt,
|
|
136
|
+
min_value=-1,
|
|
137
|
+
max_value=find_core_cnt()[0],
|
|
138
|
+
)
|
|
139
|
+
if core_cnt == -1:
|
|
140
|
+
core_cnt = find_core_cnt()[0]
|
|
141
|
+
ConfigReader.__init__(self, config_path=config_path)
|
|
142
|
+
PlottingMixin.__init__(self)
|
|
143
|
+
check_instance(
|
|
144
|
+
source=f"{self.__class__.__name__} line_attr",
|
|
145
|
+
instance=line_attr,
|
|
146
|
+
accepted_types=(list,),
|
|
147
|
+
)
|
|
148
|
+
for cnt, i in enumerate(line_attr):
|
|
149
|
+
check_valid_lst(
|
|
150
|
+
source=f"{self.__class__.__name__} line_attr {cnt}",
|
|
151
|
+
data=i,
|
|
152
|
+
valid_dtypes=(str,),
|
|
153
|
+
exact_len=3,
|
|
154
|
+
)
|
|
155
|
+
check_valid_lst(data=data_paths, valid_dtypes=(str,), min_len=1)
|
|
156
|
+
_ = [check_file_exist_and_readable(i) for i in data_paths]
|
|
157
|
+
(
|
|
158
|
+
self.video_setting,
|
|
159
|
+
self.frame_setting,
|
|
160
|
+
self.data_paths,
|
|
161
|
+
self.style_attr,
|
|
162
|
+
self.line_attr,
|
|
163
|
+
self.final_img,
|
|
164
|
+
self.core_cnt,
|
|
165
|
+
) = (
|
|
166
|
+
video_setting,
|
|
167
|
+
frame_setting,
|
|
168
|
+
data_paths,
|
|
169
|
+
style_attr,
|
|
170
|
+
line_attr,
|
|
171
|
+
final_img,
|
|
172
|
+
core_cnt,
|
|
173
|
+
)
|
|
174
|
+
if not os.path.exists(self.line_plot_dir):
|
|
175
|
+
os.makedirs(self.line_plot_dir)
|
|
176
|
+
self.color_names = get_color_dict()
|
|
177
|
+
if platform.system() == "Darwin":
|
|
178
|
+
multiprocessing.set_start_method("spawn", force=True)
|
|
179
|
+
|
|
180
|
+
@staticmethod
|
|
181
|
+
@jit(nopython=True)
|
|
182
|
+
def __insert_group_idx_column(data: np.array, group: int):
|
|
183
|
+
group_col = np.full((data.shape[0], 1), group)
|
|
184
|
+
return np.hstack((group_col, data))
|
|
185
|
+
|
|
186
|
+
def run(self):
|
|
187
|
+
print(f"Processing {len(self.data_paths)} video(s)...")
|
|
188
|
+
check_all_file_names_are_represented_in_video_log(
|
|
189
|
+
video_info_df=self.video_info_df, data_paths=self.data_paths
|
|
190
|
+
)
|
|
191
|
+
for file_cnt, file_path in enumerate(self.data_paths):
|
|
192
|
+
video_timer = SimbaTimer(start=True)
|
|
193
|
+
_, video_name, _ = get_fn_ext(file_path)
|
|
194
|
+
data_df = read_df(file_path, self.file_type)
|
|
195
|
+
try:
|
|
196
|
+
data_df.columns = self.bp_headers
|
|
197
|
+
except ValueError:
|
|
198
|
+
raise CountError(
|
|
199
|
+
msg=f"SimBA expects {self.bp_headers} columns but found {len(data_df)} columns in {file_path}",
|
|
200
|
+
source=self.__class__.__name__,
|
|
201
|
+
)
|
|
202
|
+
self.video_info, px_per_mm, fps = self.read_video_info(
|
|
203
|
+
video_name=video_name
|
|
204
|
+
)
|
|
205
|
+
self.save_video_folder = os.path.join(self.line_plot_dir, video_name)
|
|
206
|
+
self.temp_folder = os.path.join(self.line_plot_dir, video_name, "temp")
|
|
207
|
+
self.save_frame_folder_dir = os.path.join(self.line_plot_dir, video_name)
|
|
208
|
+
distances = []
|
|
209
|
+
colors = []
|
|
210
|
+
for cnt, i in enumerate(self.line_attr):
|
|
211
|
+
if i[2] not in list(self.color_names.keys()):
|
|
212
|
+
raise InvalidInputError(
|
|
213
|
+
msg=f"{i[2]} is not a valid color. Options: {list(self.color_names.keys())}.",
|
|
214
|
+
source=self.__class__.__name__,
|
|
215
|
+
)
|
|
216
|
+
colors.append(i[2])
|
|
217
|
+
bp_1, bp_2 = [f"{i[0]}_x", f"{i[0]}_y"], [f"{i[1]}_x", f"{i[1]}_y"]
|
|
218
|
+
if len(list(set(bp_1) - set(data_df.columns))) > 0:
|
|
219
|
+
raise InvalidInputError(
|
|
220
|
+
msg=f"Could not find fields {bp_1} in {file_path}",
|
|
221
|
+
source=self.__class__.__name__,
|
|
222
|
+
)
|
|
223
|
+
if len(list(set(bp_2) - set(data_df.columns))) > 0:
|
|
224
|
+
raise InvalidInputError(
|
|
225
|
+
msg=f"Could not find fields {bp_2} in {file_path}",
|
|
226
|
+
source=self.__class__.__name__,
|
|
227
|
+
)
|
|
228
|
+
distances.append(
|
|
229
|
+
FeatureExtractionMixin.framewise_euclidean_distance(
|
|
230
|
+
location_1=data_df[bp_1].values.astype(np.float64),
|
|
231
|
+
location_2=data_df[bp_2].values.astype(np.float64),
|
|
232
|
+
px_per_mm=np.float64(px_per_mm),
|
|
233
|
+
centimeter=True,
|
|
234
|
+
)
|
|
235
|
+
)
|
|
236
|
+
if self.frame_setting:
|
|
237
|
+
if os.path.exists(self.save_frame_folder_dir):
|
|
238
|
+
self.remove_a_folder(self.save_frame_folder_dir)
|
|
239
|
+
os.makedirs(self.save_frame_folder_dir)
|
|
240
|
+
if self.video_setting:
|
|
241
|
+
self.video_folder = os.path.join(self.line_plot_dir, video_name)
|
|
242
|
+
if os.path.exists(self.temp_folder):
|
|
243
|
+
self.remove_a_folder(self.temp_folder)
|
|
244
|
+
os.makedirs(self.temp_folder)
|
|
245
|
+
self.save_video_path = os.path.join(
|
|
246
|
+
self.line_plot_dir, f"{video_name}.mp4"
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
if self.final_img:
|
|
250
|
+
_ = PlottingMixin.make_line_plot(
|
|
251
|
+
data=distances,
|
|
252
|
+
colors=colors,
|
|
253
|
+
width=self.style_attr["width"],
|
|
254
|
+
height=self.style_attr["height"],
|
|
255
|
+
line_width=self.style_attr["line width"],
|
|
256
|
+
font_size=self.style_attr["font size"],
|
|
257
|
+
title="Animal distances",
|
|
258
|
+
y_lbl="distance (cm)",
|
|
259
|
+
x_lbl="time (s)",
|
|
260
|
+
x_lbl_divisor=fps,
|
|
261
|
+
y_max=self.style_attr["y_max"],
|
|
262
|
+
line_opacity=self.style_attr["opacity"],
|
|
263
|
+
save_path=os.path.join(
|
|
264
|
+
self.line_plot_dir, f"{video_name}_final_distances.png"
|
|
265
|
+
),
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
if self.video_setting or self.frame_setting:
|
|
269
|
+
if self.style_attr["y_max"] == -1:
|
|
270
|
+
self.style_attr["y_max"] = max([np.max(x) for x in distances])
|
|
271
|
+
distances = np.stack(distances, axis=1)
|
|
272
|
+
frm_range = np.arange(0, distances.shape[0])
|
|
273
|
+
frm_range = np.array_split(frm_range, self.core_cnt)
|
|
274
|
+
|
|
275
|
+
distances = np.array_split(distances, self.core_cnt)
|
|
276
|
+
distances = [
|
|
277
|
+
self.__insert_group_idx_column(data=i, group=cnt)
|
|
278
|
+
for cnt, i in enumerate(distances)
|
|
279
|
+
]
|
|
280
|
+
distances = np.concatenate(distances, axis=0)
|
|
281
|
+
print(
|
|
282
|
+
f"Creating distance plots, multiprocessing, follow progress in terminal (chunksize: {self.multiprocess_chunksize}, cores: {self.core_cnt})"
|
|
283
|
+
)
|
|
284
|
+
with multiprocessing.Pool(
|
|
285
|
+
self.core_cnt, maxtasksperchild=self.maxtasksperchild
|
|
286
|
+
) as pool:
|
|
287
|
+
constants = functools.partial(
|
|
288
|
+
distance_plotter_mp,
|
|
289
|
+
distances=distances,
|
|
290
|
+
video_setting=self.video_setting,
|
|
291
|
+
frame_setting=self.frame_setting,
|
|
292
|
+
video_name=video_name,
|
|
293
|
+
video_save_dir=self.temp_folder,
|
|
294
|
+
frame_folder_dir=self.save_frame_folder_dir,
|
|
295
|
+
style_attr=self.style_attr,
|
|
296
|
+
colors=colors,
|
|
297
|
+
fps=fps,
|
|
298
|
+
)
|
|
299
|
+
for cnt, result in enumerate(
|
|
300
|
+
pool.map(
|
|
301
|
+
constants, frm_range, chunksize=self.multiprocess_chunksize
|
|
302
|
+
)
|
|
303
|
+
):
|
|
304
|
+
print(f"Frame batch core {result} complete...")
|
|
305
|
+
pass
|
|
306
|
+
terminate_cpu_pool(pool=pool, force=False)
|
|
307
|
+
if self.video_setting:
|
|
308
|
+
concatenate_videos_in_folder(
|
|
309
|
+
in_folder=self.temp_folder,
|
|
310
|
+
save_path=self.save_video_path,
|
|
311
|
+
video_format="avi",
|
|
312
|
+
)
|
|
313
|
+
video_timer.stop_timer()
|
|
314
|
+
stdout_success(
|
|
315
|
+
msg=f"Distance visualizations created for {video_name} saved at {self.line_plot_dir}",
|
|
316
|
+
elapsed_time=video_timer.elapsed_time_str,
|
|
317
|
+
)
|
|
318
|
+
self.timer.stop_timer()
|
|
319
|
+
stdout_success(
|
|
320
|
+
msg=f"Distance visualizations complete for {len(self.data_paths)} video(s)",
|
|
321
|
+
elapsed_time=self.timer.elapsed_time_str,
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
# style_attr = {'width': 640, 'height': 480, 'line width': 6, 'font size': 12, 'y_max': -1, 'opacity': 0.5}
|
|
326
|
+
# line_attr = [['Center_1', 'Center_2', 'Green'], ['Ear_left_2', 'Ear_right_2', 'Red']]
|
|
327
|
+
# test = DistancePlotterMultiCore(config_path=r'/Users/simon/Desktop/envs/simba/troubleshooting/two_black_animals_14bp/project_folder/project_config.ini',
|
|
328
|
+
# frame_setting=True,
|
|
329
|
+
# video_setting=True,
|
|
330
|
+
# style_attr=style_attr,
|
|
331
|
+
# final_img=True,
|
|
332
|
+
# data_paths=['/Users/simon/Desktop/envs/simba/troubleshooting/two_black_animals_14bp/project_folder/csv/outlier_corrected_movement_location/Together_1.csv'],
|
|
333
|
+
# line_attr=line_attr,
|
|
334
|
+
# core_cnt=-1)
|
|
335
|
+
# test.run()
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
# style_attr = {'width': 640, 'height': 480, 'line width': 6, 'font size': 8, 'y_max': 'auto', 'opacity': 0.9}
|
|
339
|
+
# line_attr = {0: ['Center_1', 'Center_2', 'Green'], 1: ['Ear_left_2', 'Ear_left_1', 'Red']}
|
|
340
|
+
#
|
|
341
|
+
# test = DistancePlotterMultiCore(config_path=r'/Users/simon/Desktop/envs/troubleshooting/two_black_animals_14bp/project_folder/project_config.ini',
|
|
342
|
+
# frame_setting=False,
|
|
343
|
+
# video_setting=True,
|
|
344
|
+
# style_attr=style_attr,
|
|
345
|
+
# final_img=True,
|
|
346
|
+
# files_found=['/Users/simon/Desktop/envs/troubleshooting/two_black_animals_14bp/project_folder/csv/machine_results/Together_1.csv'],
|
|
347
|
+
# line_attr=line_attr,
|
|
348
|
+
# core_cnt=3)
|
|
349
|
+
# test.create_distance_plot()
|
|
350
|
+
# #
|
|
351
|
+
# style_attr = {'width': 640, 'height': 480, 'line width': 6, 'font size': 8}
|
|
352
|
+
# line_attr = {0: ['Termite_1_Head_1', 'Termite_1_Thorax_1', 'Dark-red']}
|
|
353
|
+
#
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
# style_attr = {'width': 640, 'height': 480, 'line width': 6, 'font size': 8, 'opacity': 0.5, 'y_max': 'auto'}
|
|
357
|
+
# line_attr = {0: ['Center_1', 'Center_2', 'Green'], 1: ['Ear_left_2', 'Ear_left_1', 'Red']}
|
|
358
|
+
#
|
|
359
|
+
# test = DistancePlotterMultiCore(config_path=r'/Users/simon/Desktop/envs/troubleshooting/two_black_animals_14bp/project_folder/project_config.ini',
|
|
360
|
+
# frame_setting=False,
|
|
361
|
+
# video_setting=True,
|
|
362
|
+
# style_attr=style_attr,
|
|
363
|
+
# final_img=False,
|
|
364
|
+
# files_found=['/Users/simon/Desktop/envs/troubleshooting/two_black_animals_14bp/project_folder/csv/machine_results/Together_1.csv'],
|
|
365
|
+
# line_attr=line_attr,
|
|
366
|
+
# core_cnt=5)
|
|
367
|
+
# test.create_distance_plot()
|
|
368
|
+
|
|
369
|
+
# style_attr = {'width': 640, 'height': 480, 'line width': 6, 'font size': 8}
|
|
370
|
+
# line_attr = {0: ['Termite_1_Head_1', 'Termite_1_Thorax_1', 'Dark-red']}
|
|
371
|
+
|
|
372
|
+
# test = DistancePlotterSingleCore(config_path=r'/Users/simon/Desktop/envs/troubleshooting/Termites_5/project_folder/project_config.ini',
|
|
373
|
+
# frame_setting=False,
|
|
374
|
+
# video_setting=True,
|
|
375
|
+
# style_attr=style_attr,
|
|
376
|
+
# files_found=['/Users/simon/Desktop/envs/troubleshooting/Termites_5/project_folder/csv/outlier_corrected_movement_location/termites_1.csv'],
|
|
377
|
+
# line_attr=line_attr)
|
|
378
|
+
# test.create_distance_plot()
|