simba-uw-tf-dev 4.6.1__py3-none-any.whl → 4.6.3__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/SimBA.py +2 -2
- simba/assets/icons/frames_2.png +0 -0
- simba/data_processors/agg_clf_counter_mp.py +52 -53
- simba/data_processors/cuda/image.py +3 -1
- simba/data_processors/cue_light_analyzer.py +5 -9
- simba/mixins/geometry_mixin.py +14 -28
- simba/mixins/image_mixin.py +10 -14
- simba/mixins/train_model_mixin.py +2 -2
- 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/frame_mergerer_ffmpeg.py +137 -137
- simba/plotting/gantt_creator_mp.py +59 -31
- simba/plotting/geometry_plotter.py +270 -272
- simba/plotting/heat_mapper_clf_mp.py +2 -4
- 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 +27 -32
- simba/plotting/probability_plot_creator_mp.py +288 -288
- simba/plotting/roi_plotter_mp.py +29 -30
- 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 +31 -27
- simba/plotting/yolo_pose_visualizer.py +32 -34
- simba/plotting/yolo_seg_visualizer.py +2 -3
- simba/roi_tools/roi_aggregate_stats_mp.py +4 -3
- simba/roi_tools/roi_clf_calculator_mp.py +3 -3
- simba/sandbox/cuda/egocentric_rotator.py +374 -0
- simba/sandbox/get_cpu_pool.py +5 -0
- simba/ui/pop_ups/clf_add_remove_print_pop_up.py +3 -1
- simba/ui/pop_ups/egocentric_alignment_pop_up.py +6 -3
- simba/ui/pop_ups/multiple_videos_to_frames_popup.py +10 -11
- simba/ui/pop_ups/single_video_to_frames_popup.py +10 -10
- simba/ui/pop_ups/video_processing_pop_up.py +63 -63
- simba/ui/tkinter_functions.py +7 -1
- simba/utils/data.py +89 -12
- simba/utils/enums.py +1 -0
- simba/utils/printing.py +9 -8
- simba/utils/read_write.py +3726 -3721
- simba/video_processors/clahe_ui.py +65 -22
- simba/video_processors/egocentric_video_rotator.py +6 -9
- simba/video_processors/video_processing.py +21 -10
- simba/video_processors/videos_to_frames.py +3 -2
- {simba_uw_tf_dev-4.6.1.dist-info → simba_uw_tf_dev-4.6.3.dist-info}/METADATA +1 -1
- {simba_uw_tf_dev-4.6.1.dist-info → simba_uw_tf_dev-4.6.3.dist-info}/RECORD +53 -50
- {simba_uw_tf_dev-4.6.1.dist-info → simba_uw_tf_dev-4.6.3.dist-info}/LICENSE +0 -0
- {simba_uw_tf_dev-4.6.1.dist-info → simba_uw_tf_dev-4.6.3.dist-info}/WHEEL +0 -0
- {simba_uw_tf_dev-4.6.1.dist-info → simba_uw_tf_dev-4.6.3.dist-info}/entry_points.txt +0 -0
- {simba_uw_tf_dev-4.6.1.dist-info → simba_uw_tf_dev-4.6.3.dist-info}/top_level.txt +0 -0
|
@@ -1,137 +1,137 @@
|
|
|
1
|
-
__author__ = "Simon Nilsson; sronilsson@gmail.com"
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
import shutil
|
|
5
|
-
from datetime import datetime
|
|
6
|
-
from typing import List, Optional, Union
|
|
7
|
-
|
|
8
|
-
try:
|
|
9
|
-
from typing import Literal
|
|
10
|
-
except ImportError:
|
|
11
|
-
from typing_extensions import Literal
|
|
12
|
-
|
|
13
|
-
from simba.mixins.config_reader import ConfigReader
|
|
14
|
-
from simba.utils.checks import (check_ffmpeg_available,
|
|
15
|
-
check_file_exist_and_readable, check_int,
|
|
16
|
-
check_nvidea_gpu_available, check_str,
|
|
17
|
-
|
|
18
|
-
from simba.utils.enums import Paths, TagNames
|
|
19
|
-
from simba.utils.errors import FFMPEGCodecGPUError
|
|
20
|
-
from simba.utils.printing import SimbaTimer, log_event, stdout_success
|
|
21
|
-
from simba.utils.read_write import copy_files_to_directory, get_fn_ext
|
|
22
|
-
from simba.video_processors.video_processing import (
|
|
23
|
-
horizontal_video_concatenator, mixed_mosaic_concatenator,
|
|
24
|
-
mosaic_concatenator, vertical_video_concatenator)
|
|
25
|
-
|
|
26
|
-
HORIZONTAL = "horizontal"
|
|
27
|
-
VERTICAL = "vertical"
|
|
28
|
-
MOSAIC = "mosaic"
|
|
29
|
-
MIXED_MOSAIC = "mixed_mosaic"
|
|
30
|
-
ACCEPTED_TYPES = [HORIZONTAL, VERTICAL, MOSAIC, MIXED_MOSAIC]
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class FrameMergererFFmpeg(ConfigReader):
|
|
34
|
-
"""
|
|
35
|
-
Merge separate visualizations of classifications, descriptive statistics etc., into single video mosaic.
|
|
36
|
-
|
|
37
|
-
.. note::
|
|
38
|
-
`GitHub tutorial <https://github.com/sgoldenlab/simba/blob/master/docs/tutorial.md#step-12-merge-frames>`_.
|
|
39
|
-
|
|
40
|
-
.. image:: _static/img/mosaic_videos.gif
|
|
41
|
-
:width: 600
|
|
42
|
-
:align: center
|
|
43
|
-
|
|
44
|
-
:parameter str config_path: Optional path to SimBA project config file in Configparser format.
|
|
45
|
-
:parameter Literal["horizontal", "vertical", "mosaic", "mixed_mosaic"] concat_type: Type of concatenation. OPTIONS: 'horizontal', 'vertical', 'mosaic', 'mixed_mosaic'.
|
|
46
|
-
:parameter List[Union[str, os.PathLike]] video_paths: List with videos to concatenate.
|
|
47
|
-
:param int quality: Video quality (CRF value). Lower values = higher quality. Range 0-52. Default 23.
|
|
48
|
-
:parameter Optional[int] video_height: Optional height of the canatenated videos. Required if concat concat_type is not mixed_mosaic.
|
|
49
|
-
:parameter int video_width: Optional wisth of the canatenated videos. Required if concat concat_type is not mixed_mosaic.
|
|
50
|
-
:parameter Optional[bool] gpu: If True, use NVIDEA FFMpeg GPU codecs. Default False.
|
|
51
|
-
|
|
52
|
-
:example:
|
|
53
|
-
>>> video_paths = ['/Users/simon/Desktop/envs/simba/troubleshooting/mouse_open_field/project_folder/videos/SI_DAY3_308_CD1_PRESENT_downsampled.mp4', '/Users/simon/Desktop/envs/simba/troubleshooting/mouse_open_field/project_folder/videos/SI_DAY3_308_CD1_PRESENT_downsampled.mp4']
|
|
54
|
-
>>> merger = FrameMergererFFmpeg(config_path='/Users/simon/Desktop/envs/simba/troubleshooting/two_black_animals_14bp/project_folder/project_config.ini', video_paths=videos, video_height=600, video_width=600, concat_type='mosaic')
|
|
55
|
-
>>> merger.run()
|
|
56
|
-
"""
|
|
57
|
-
|
|
58
|
-
def __init__( self,
|
|
59
|
-
concat_type: Literal["horizontal", "vertical", "mosaic", "mixed_mosaic"],
|
|
60
|
-
video_paths: List[Union[str, os.PathLike]],
|
|
61
|
-
video_height: Optional[int] = None,
|
|
62
|
-
video_width: Optional[int] = None,
|
|
63
|
-
config_path: Optional[str] = None,
|
|
64
|
-
quality: int = 23,
|
|
65
|
-
gpu: bool = False):
|
|
66
|
-
|
|
67
|
-
if gpu and not check_nvidea_gpu_available():
|
|
68
|
-
raise FFMPEGCodecGPUError(msg="NVIDEA GPU not available (as evaluated by nvidea-smi returning None", source=self.__class__.__name__)
|
|
69
|
-
check_ffmpeg_available()
|
|
70
|
-
check_str(name=f"{FrameMergererFFmpeg.__name__} concat_type", value=concat_type, options=ACCEPTED_TYPES)
|
|
71
|
-
check_valid_lst(data=video_paths, source=f"{self.__class__.__name__} video_paths", valid_dtypes=(str,), min_len=2)
|
|
72
|
-
check_valid_boolean(value=gpu, source=f'{self.__class__.__name__} gpu', raise_error=True)
|
|
73
|
-
self.quality = 23 if not check_int(name='quality', value=quality, min_value=0, max_value=52, raise_error=False)[0] else int(quality)
|
|
74
|
-
for i in video_paths:
|
|
75
|
-
check_file_exist_and_readable(file_path=i)
|
|
76
|
-
if concat_type != MIXED_MOSAIC:
|
|
77
|
-
check_int(name=f"{FrameMergererFFmpeg.__name__} video_height", value=video_height, min_value=0)
|
|
78
|
-
check_int(name=f"{FrameMergererFFmpeg.__name__} video_width", value=video_height, min_value=0)
|
|
79
|
-
if config_path is not None:
|
|
80
|
-
ConfigReader.__init__(self, config_path=config_path)
|
|
81
|
-
log_event(logger_name=str(__class__.__name__), log_type=TagNames.CLASS_INIT.value, msg=self.create_log_msg_from_init_args(locals=locals()))
|
|
82
|
-
self.output_dir = os.path.join(self.project_path, Paths.CONCAT_VIDEOS_DIR.value)
|
|
83
|
-
self.output_path = os.path.join(self.project_path, Paths.CONCAT_VIDEOS_DIR.value, f"merged_video_{self.datetime}.mp4")
|
|
84
|
-
else:
|
|
85
|
-
self.timer = SimbaTimer(start=True)
|
|
86
|
-
self.datetime = datetime.now().strftime("%Y%m%d%H%M%S")
|
|
87
|
-
self.output_dir, _, _ = get_fn_ext(filepath=video_paths[0])
|
|
88
|
-
self.output_path = os.path.join(self.output_dir, f"merged_video_{self.datetime}.mp4")
|
|
89
|
-
|
|
90
|
-
self.video_height, self.video_width, self.gpu = video_height, video_width, gpu
|
|
91
|
-
self.video_paths, self.concat_type = video_paths, concat_type
|
|
92
|
-
if not os.path.exists(self.output_dir): os.makedirs(self.output_dir)
|
|
93
|
-
|
|
94
|
-
def run(self):
|
|
95
|
-
if self.concat_type == HORIZONTAL:
|
|
96
|
-
_ = horizontal_video_concatenator(video_paths=self.video_paths, save_path=self.output_path, height_px=self.video_height, gpu=self.gpu, quality=self.quality, verbose=True)
|
|
97
|
-
elif self.concat_type == VERTICAL:
|
|
98
|
-
_ = vertical_video_concatenator(video_paths=self.video_paths, save_path=self.output_path, width_px=self.video_width, gpu=self.gpu, quality=self.quality, verbose=True)
|
|
99
|
-
elif self.concat_type == MOSAIC:
|
|
100
|
-
_ = mosaic_concatenator(video_paths=self.video_paths, save_path=self.output_path, width_px=self.video_width, height_px=self.video_height, gpu=self.gpu, quality=self.quality, verbose=True)
|
|
101
|
-
else:
|
|
102
|
-
_ = mixed_mosaic_concatenator(video_paths=self.video_paths, save_path=self.output_path, gpu=self.gpu, verbose=True)
|
|
103
|
-
self.timer.stop_timer()
|
|
104
|
-
stdout_success(msg=f"Merged video saved at {self.output_path}", source=self.__class__.__name__, elapsed_time=self.timer.elapsed_time_str)
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
# videos = ['/Users/simon/Desktop/envs/simba/troubleshooting/mouse_open_field/project_folder/videos/SI_DAY3_308_CD1_PRESENT_downsampled.mp4', '/Users/simon/Desktop/envs/simba/troubleshooting/mouse_open_field/project_folder/videos/SI_DAY3_308_CD1_PRESENT_downsampled.mp4']
|
|
108
|
-
#
|
|
109
|
-
# merger = FrameMergererFFmpeg(config_path='/Users/simon/Desktop/envs/simba/troubleshooting/two_black_animals_14bp/project_folder/project_config.ini',
|
|
110
|
-
# video_paths=videos,
|
|
111
|
-
# video_height=600,
|
|
112
|
-
# video_width=600,
|
|
113
|
-
# concat_type='vertical') #horizontal, vertical, mosaic, mixed_mosaic
|
|
114
|
-
# merger.run()
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
#
|
|
118
|
-
# FrameMergererFFmpeg(config_path=None,
|
|
119
|
-
# frame_types={'Video 1': '/Users/simon/Desktop/envs/troubleshooting/two_black_animals_14bp/project_folder/videos/Together_1.avi',
|
|
120
|
-
# 'Video 2': '/Users/simon/Desktop/envs/troubleshooting/two_black_animals_14bp/project_folder/videos/Together_1.avi'},
|
|
121
|
-
# video_height=640,
|
|
122
|
-
# video_width=480,
|
|
123
|
-
# concat_type='vertical') #horizontal, vertical, mosaic, mixed_mosaic
|
|
124
|
-
#
|
|
125
|
-
#
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
# FrameMergererFFmpeg(config_path=None,
|
|
129
|
-
# frame_types={'Video 1': r'C:\Users\Nape_Computer_2\Desktop\test_videos\Box1_PM2_day_5_20211104T171021.mp4',
|
|
130
|
-
# 'Video 2': r'C:\Users\Nape_Computer_2\Desktop\test_videos\Box1_PM2_day_5_20211104T171021.mp4',
|
|
131
|
-
# 'Video 3': r'C:\Users\Nape_Computer_2\Desktop\test_videos\Box1_PM2_day_5_20211104T171021.mp4',
|
|
132
|
-
# 'Video 4': r'C:\Users\Nape_Computer_2\Desktop\test_videos\Box1_PM2_day_5_20211104T171021.mp4'},
|
|
133
|
-
# video_height=640,
|
|
134
|
-
# video_width=480,
|
|
135
|
-
# concat_type='mixed_mosaic',
|
|
136
|
-
# gpu=False) #horizontal, vertical, mosaic, mixed_mosaic
|
|
137
|
-
#
|
|
1
|
+
__author__ = "Simon Nilsson; sronilsson@gmail.com"
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import shutil
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from typing import List, Optional, Union
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
from typing import Literal
|
|
10
|
+
except ImportError:
|
|
11
|
+
from typing_extensions import Literal
|
|
12
|
+
|
|
13
|
+
from simba.mixins.config_reader import ConfigReader
|
|
14
|
+
from simba.utils.checks import (check_ffmpeg_available,
|
|
15
|
+
check_file_exist_and_readable, check_int,
|
|
16
|
+
check_nvidea_gpu_available, check_str,
|
|
17
|
+
check_valid_boolean, check_valid_lst)
|
|
18
|
+
from simba.utils.enums import Paths, TagNames
|
|
19
|
+
from simba.utils.errors import FFMPEGCodecGPUError
|
|
20
|
+
from simba.utils.printing import SimbaTimer, log_event, stdout_success
|
|
21
|
+
from simba.utils.read_write import copy_files_to_directory, get_fn_ext
|
|
22
|
+
from simba.video_processors.video_processing import (
|
|
23
|
+
horizontal_video_concatenator, mixed_mosaic_concatenator,
|
|
24
|
+
mosaic_concatenator, vertical_video_concatenator)
|
|
25
|
+
|
|
26
|
+
HORIZONTAL = "horizontal"
|
|
27
|
+
VERTICAL = "vertical"
|
|
28
|
+
MOSAIC = "mosaic"
|
|
29
|
+
MIXED_MOSAIC = "mixed_mosaic"
|
|
30
|
+
ACCEPTED_TYPES = [HORIZONTAL, VERTICAL, MOSAIC, MIXED_MOSAIC]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class FrameMergererFFmpeg(ConfigReader):
|
|
34
|
+
"""
|
|
35
|
+
Merge separate visualizations of classifications, descriptive statistics etc., into single video mosaic.
|
|
36
|
+
|
|
37
|
+
.. note::
|
|
38
|
+
`GitHub tutorial <https://github.com/sgoldenlab/simba/blob/master/docs/tutorial.md#step-12-merge-frames>`_.
|
|
39
|
+
|
|
40
|
+
.. image:: _static/img/mosaic_videos.gif
|
|
41
|
+
:width: 600
|
|
42
|
+
:align: center
|
|
43
|
+
|
|
44
|
+
:parameter str config_path: Optional path to SimBA project config file in Configparser format.
|
|
45
|
+
:parameter Literal["horizontal", "vertical", "mosaic", "mixed_mosaic"] concat_type: Type of concatenation. OPTIONS: 'horizontal', 'vertical', 'mosaic', 'mixed_mosaic'.
|
|
46
|
+
:parameter List[Union[str, os.PathLike]] video_paths: List with videos to concatenate.
|
|
47
|
+
:param int quality: Video quality (CRF value). Lower values = higher quality. Range 0-52. Default 23.
|
|
48
|
+
:parameter Optional[int] video_height: Optional height of the canatenated videos. Required if concat concat_type is not mixed_mosaic.
|
|
49
|
+
:parameter int video_width: Optional wisth of the canatenated videos. Required if concat concat_type is not mixed_mosaic.
|
|
50
|
+
:parameter Optional[bool] gpu: If True, use NVIDEA FFMpeg GPU codecs. Default False.
|
|
51
|
+
|
|
52
|
+
:example:
|
|
53
|
+
>>> video_paths = ['/Users/simon/Desktop/envs/simba/troubleshooting/mouse_open_field/project_folder/videos/SI_DAY3_308_CD1_PRESENT_downsampled.mp4', '/Users/simon/Desktop/envs/simba/troubleshooting/mouse_open_field/project_folder/videos/SI_DAY3_308_CD1_PRESENT_downsampled.mp4']
|
|
54
|
+
>>> merger = FrameMergererFFmpeg(config_path='/Users/simon/Desktop/envs/simba/troubleshooting/two_black_animals_14bp/project_folder/project_config.ini', video_paths=videos, video_height=600, video_width=600, concat_type='mosaic')
|
|
55
|
+
>>> merger.run()
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
def __init__( self,
|
|
59
|
+
concat_type: Literal["horizontal", "vertical", "mosaic", "mixed_mosaic"],
|
|
60
|
+
video_paths: List[Union[str, os.PathLike]],
|
|
61
|
+
video_height: Optional[int] = None,
|
|
62
|
+
video_width: Optional[int] = None,
|
|
63
|
+
config_path: Optional[str] = None,
|
|
64
|
+
quality: int = 23,
|
|
65
|
+
gpu: bool = False):
|
|
66
|
+
|
|
67
|
+
if gpu and not check_nvidea_gpu_available():
|
|
68
|
+
raise FFMPEGCodecGPUError(msg="NVIDEA GPU not available (as evaluated by nvidea-smi returning None", source=self.__class__.__name__)
|
|
69
|
+
check_ffmpeg_available()
|
|
70
|
+
check_str(name=f"{FrameMergererFFmpeg.__name__} concat_type", value=concat_type, options=ACCEPTED_TYPES)
|
|
71
|
+
check_valid_lst(data=video_paths, source=f"{self.__class__.__name__} video_paths", valid_dtypes=(str,), min_len=2)
|
|
72
|
+
check_valid_boolean(value=gpu, source=f'{self.__class__.__name__} gpu', raise_error=True)
|
|
73
|
+
self.quality = 23 if not check_int(name='quality', value=quality, min_value=0, max_value=52, raise_error=False)[0] else int(quality)
|
|
74
|
+
for i in video_paths:
|
|
75
|
+
check_file_exist_and_readable(file_path=i)
|
|
76
|
+
if concat_type != MIXED_MOSAIC:
|
|
77
|
+
check_int(name=f"{FrameMergererFFmpeg.__name__} video_height", value=video_height, min_value=0)
|
|
78
|
+
check_int(name=f"{FrameMergererFFmpeg.__name__} video_width", value=video_height, min_value=0)
|
|
79
|
+
if config_path is not None:
|
|
80
|
+
ConfigReader.__init__(self, config_path=config_path)
|
|
81
|
+
log_event(logger_name=str(__class__.__name__), log_type=TagNames.CLASS_INIT.value, msg=self.create_log_msg_from_init_args(locals=locals()))
|
|
82
|
+
self.output_dir = os.path.join(self.project_path, Paths.CONCAT_VIDEOS_DIR.value)
|
|
83
|
+
self.output_path = os.path.join(self.project_path, Paths.CONCAT_VIDEOS_DIR.value, f"merged_video_{self.datetime}.mp4")
|
|
84
|
+
else:
|
|
85
|
+
self.timer = SimbaTimer(start=True)
|
|
86
|
+
self.datetime = datetime.now().strftime("%Y%m%d%H%M%S")
|
|
87
|
+
self.output_dir, _, _ = get_fn_ext(filepath=video_paths[0])
|
|
88
|
+
self.output_path = os.path.join(self.output_dir, f"merged_video_{self.datetime}.mp4")
|
|
89
|
+
|
|
90
|
+
self.video_height, self.video_width, self.gpu = video_height, video_width, gpu
|
|
91
|
+
self.video_paths, self.concat_type = video_paths, concat_type
|
|
92
|
+
if not os.path.exists(self.output_dir): os.makedirs(self.output_dir)
|
|
93
|
+
|
|
94
|
+
def run(self):
|
|
95
|
+
if self.concat_type == HORIZONTAL:
|
|
96
|
+
_ = horizontal_video_concatenator(video_paths=self.video_paths, save_path=self.output_path, height_px=self.video_height, gpu=self.gpu, quality=self.quality, verbose=True)
|
|
97
|
+
elif self.concat_type == VERTICAL:
|
|
98
|
+
_ = vertical_video_concatenator(video_paths=self.video_paths, save_path=self.output_path, width_px=self.video_width, gpu=self.gpu, quality=self.quality, verbose=True)
|
|
99
|
+
elif self.concat_type == MOSAIC:
|
|
100
|
+
_ = mosaic_concatenator(video_paths=self.video_paths, save_path=self.output_path, width_px=self.video_width, height_px=self.video_height, gpu=self.gpu, quality=self.quality, verbose=True)
|
|
101
|
+
else:
|
|
102
|
+
_ = mixed_mosaic_concatenator(video_paths=self.video_paths, save_path=self.output_path, gpu=self.gpu, verbose=True)
|
|
103
|
+
self.timer.stop_timer()
|
|
104
|
+
stdout_success(msg=f"Merged video saved at {self.output_path}", source=self.__class__.__name__, elapsed_time=self.timer.elapsed_time_str)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
# videos = ['/Users/simon/Desktop/envs/simba/troubleshooting/mouse_open_field/project_folder/videos/SI_DAY3_308_CD1_PRESENT_downsampled.mp4', '/Users/simon/Desktop/envs/simba/troubleshooting/mouse_open_field/project_folder/videos/SI_DAY3_308_CD1_PRESENT_downsampled.mp4']
|
|
108
|
+
#
|
|
109
|
+
# merger = FrameMergererFFmpeg(config_path='/Users/simon/Desktop/envs/simba/troubleshooting/two_black_animals_14bp/project_folder/project_config.ini',
|
|
110
|
+
# video_paths=videos,
|
|
111
|
+
# video_height=600,
|
|
112
|
+
# video_width=600,
|
|
113
|
+
# concat_type='vertical') #horizontal, vertical, mosaic, mixed_mosaic
|
|
114
|
+
# merger.run()
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
#
|
|
118
|
+
# FrameMergererFFmpeg(config_path=None,
|
|
119
|
+
# frame_types={'Video 1': '/Users/simon/Desktop/envs/troubleshooting/two_black_animals_14bp/project_folder/videos/Together_1.avi',
|
|
120
|
+
# 'Video 2': '/Users/simon/Desktop/envs/troubleshooting/two_black_animals_14bp/project_folder/videos/Together_1.avi'},
|
|
121
|
+
# video_height=640,
|
|
122
|
+
# video_width=480,
|
|
123
|
+
# concat_type='vertical') #horizontal, vertical, mosaic, mixed_mosaic
|
|
124
|
+
#
|
|
125
|
+
#
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
# FrameMergererFFmpeg(config_path=None,
|
|
129
|
+
# frame_types={'Video 1': r'C:\Users\Nape_Computer_2\Desktop\test_videos\Box1_PM2_day_5_20211104T171021.mp4',
|
|
130
|
+
# 'Video 2': r'C:\Users\Nape_Computer_2\Desktop\test_videos\Box1_PM2_day_5_20211104T171021.mp4',
|
|
131
|
+
# 'Video 3': r'C:\Users\Nape_Computer_2\Desktop\test_videos\Box1_PM2_day_5_20211104T171021.mp4',
|
|
132
|
+
# 'Video 4': r'C:\Users\Nape_Computer_2\Desktop\test_videos\Box1_PM2_day_5_20211104T171021.mp4'},
|
|
133
|
+
# video_height=640,
|
|
134
|
+
# video_width=480,
|
|
135
|
+
# concat_type='mixed_mosaic',
|
|
136
|
+
# gpu=False) #horizontal, vertical, mosaic, mixed_mosaic
|
|
137
|
+
#
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
__author__ = "Simon Nilsson; sronilsson@gmail.com"
|
|
2
2
|
|
|
3
|
-
import time
|
|
4
3
|
import warnings
|
|
5
4
|
|
|
6
5
|
warnings.simplefilter(action="ignore", category=FutureWarning)
|
|
@@ -9,10 +8,14 @@ import multiprocessing
|
|
|
9
8
|
import os
|
|
10
9
|
import platform
|
|
11
10
|
from typing import List, Optional, Union
|
|
11
|
+
from copy import deepcopy
|
|
12
12
|
|
|
13
|
+
import gc
|
|
13
14
|
import cv2
|
|
14
15
|
import numpy as np
|
|
15
16
|
import pandas as pd
|
|
17
|
+
import matplotlib
|
|
18
|
+
matplotlib.use('Agg')
|
|
16
19
|
|
|
17
20
|
from simba.mixins.config_reader import ConfigReader
|
|
18
21
|
from simba.mixins.plotting_mixin import PlottingMixin
|
|
@@ -20,13 +23,13 @@ from simba.utils.checks import (
|
|
|
20
23
|
check_all_file_names_are_represented_in_video_log,
|
|
21
24
|
check_file_exist_and_readable, check_int, check_str,
|
|
22
25
|
check_that_column_exist, check_valid_boolean, check_valid_lst)
|
|
23
|
-
from simba.utils.data import create_color_palette, detect_bouts
|
|
26
|
+
from simba.utils.data import (create_color_palette, detect_bouts, terminate_cpu_pool, get_cpu_pool)
|
|
24
27
|
from simba.utils.enums import Formats, Options
|
|
25
28
|
from simba.utils.errors import NoSpecifiedOutputError
|
|
26
29
|
from simba.utils.printing import SimbaTimer, stdout_success
|
|
27
30
|
from simba.utils.read_write import (concatenate_videos_in_folder,
|
|
28
31
|
create_directory, find_core_cnt,
|
|
29
|
-
get_fn_ext, read_df)
|
|
32
|
+
get_fn_ext, read_df, get_current_time)
|
|
30
33
|
|
|
31
34
|
HEIGHT = "height"
|
|
32
35
|
WIDTH = "width"
|
|
@@ -78,11 +81,17 @@ def gantt_creator_mp(data: np.array,
|
|
|
78
81
|
cv2.imwrite(frame_save_path, plot)
|
|
79
82
|
if video_setting:
|
|
80
83
|
video_writer.write(plot)
|
|
81
|
-
|
|
84
|
+
# Clear memory after each frame
|
|
85
|
+
del plot
|
|
86
|
+
if current_frm % 100 == 0: # Periodic garbage collection to prevent memory buildup
|
|
87
|
+
gc.collect()
|
|
88
|
+
print(f"[{get_current_time()}] Gantt frame created: {current_frm + 1}, Video: {video_name}, Processing core: {batch_id + 1}")
|
|
82
89
|
|
|
83
90
|
if video_setting:
|
|
84
91
|
video_writer.release()
|
|
92
|
+
del video_writer
|
|
85
93
|
|
|
94
|
+
gc.collect()
|
|
86
95
|
return batch_id
|
|
87
96
|
|
|
88
97
|
|
|
@@ -120,7 +129,7 @@ class GanttCreatorMultiprocess(ConfigReader, PlottingMixin):
|
|
|
120
129
|
|
|
121
130
|
def __init__(self,
|
|
122
131
|
config_path: Union[str, os.PathLike],
|
|
123
|
-
data_paths: List[Union[str, os.PathLike]],
|
|
132
|
+
data_paths: Optional[Union[Union[str, os.PathLike], List[Union[str, os.PathLike]]]] = None,
|
|
124
133
|
frame_setting: Optional[bool] = False,
|
|
125
134
|
video_setting: Optional[bool] = False,
|
|
126
135
|
last_frm_setting: Optional[bool] = True,
|
|
@@ -129,14 +138,13 @@ class GanttCreatorMultiprocess(ConfigReader, PlottingMixin):
|
|
|
129
138
|
font_size: int = 8,
|
|
130
139
|
font_rotation: int = 45,
|
|
131
140
|
palette: str = 'Set1',
|
|
132
|
-
core_cnt:
|
|
141
|
+
core_cnt: int = -1,
|
|
133
142
|
hhmmss: bool = False):
|
|
134
143
|
|
|
135
144
|
check_file_exist_and_readable(file_path=config_path)
|
|
136
145
|
if (not frame_setting) and (not video_setting) and (not last_frm_setting):
|
|
137
146
|
raise NoSpecifiedOutputError(msg="SIMBA ERROR: Please select gantt videos, frames, and/or last frame.", source=self.__class__.__name__)
|
|
138
147
|
check_file_exist_and_readable(file_path=config_path)
|
|
139
|
-
check_valid_lst(data=data_paths, source=f'{self.__class__.__name__} data_paths', valid_dtypes=(str,), min_len=1)
|
|
140
148
|
check_int(value=width, min_value=1, name=f'{self.__class__.__name__} width')
|
|
141
149
|
check_int(value=height, min_value=1, name=f'{self.__class__.__name__} height')
|
|
142
150
|
check_int(value=font_size, min_value=1, name=f'{self.__class__.__name__} font_size')
|
|
@@ -144,11 +152,18 @@ class GanttCreatorMultiprocess(ConfigReader, PlottingMixin):
|
|
|
144
152
|
check_valid_boolean(value=hhmmss, source=f'{self.__class__.__name__} hhmmss', raise_error=False)
|
|
145
153
|
palettes = Options.PALETTE_OPTIONS_CATEGORICAL.value + Options.PALETTE_OPTIONS.value
|
|
146
154
|
check_str(name=f'{self.__class__.__name__} palette', value=palette, options=palettes)
|
|
147
|
-
for file_path in data_paths: check_file_exist_and_readable(file_path=file_path)
|
|
148
155
|
check_int(name=f"{self.__class__.__name__} core_cnt",value=core_cnt, min_value=-1, unaccepted_vals=[0], max_value=find_core_cnt()[0])
|
|
149
156
|
self.core_cnt = find_core_cnt()[0] if core_cnt == -1 or core_cnt > find_core_cnt()[0] else core_cnt
|
|
150
157
|
self.width, self.height, self.font_size, self.font_rotation, self.hhmmss = width, height, font_size, font_rotation, hhmmss
|
|
151
158
|
ConfigReader.__init__(self, config_path=config_path, create_logger=False)
|
|
159
|
+
if isinstance(data_paths, list):
|
|
160
|
+
check_valid_lst(data=data_paths, source=f'{self.__class__.__name__} data_paths', valid_dtypes=(str,), min_len=1)
|
|
161
|
+
elif isinstance(data_paths, str):
|
|
162
|
+
check_file_exist_and_readable(file_path=data_paths)
|
|
163
|
+
data_paths = [data_paths]
|
|
164
|
+
else:
|
|
165
|
+
data_paths = deepcopy(self.machine_results_paths)
|
|
166
|
+
for file_path in data_paths: check_file_exist_and_readable(file_path=file_path)
|
|
152
167
|
PlottingMixin.__init__(self)
|
|
153
168
|
self.clr_lst = create_color_palette(pallete_name=palette, increments=len(self.body_parts_lst) + 1, as_int=True, as_rgb_ratio=True)
|
|
154
169
|
self.frame_setting, self.video_setting, self.data_paths, self.last_frm_setting = frame_setting, video_setting,data_paths, last_frm_setting
|
|
@@ -159,6 +174,10 @@ class GanttCreatorMultiprocess(ConfigReader, PlottingMixin):
|
|
|
159
174
|
|
|
160
175
|
def run(self):
|
|
161
176
|
check_all_file_names_are_represented_in_video_log(video_info_df=self.video_info_df, data_paths=self.data_paths)
|
|
177
|
+
if self.video_setting or self.frame_setting:
|
|
178
|
+
self.pool = get_cpu_pool(core_cnt=self.core_cnt, maxtasksperchild=self.maxtasksperchild, verbose=True, source=self.__class__.__name__)
|
|
179
|
+
else:
|
|
180
|
+
self.pool = None
|
|
162
181
|
for file_cnt, file_path in enumerate(self.data_paths):
|
|
163
182
|
video_timer = SimbaTimer(start=True)
|
|
164
183
|
_, self.video_name, _ = get_fn_ext(file_path)
|
|
@@ -192,33 +211,31 @@ class GanttCreatorMultiprocess(ConfigReader, PlottingMixin):
|
|
|
192
211
|
if self.video_setting or self.frame_setting:
|
|
193
212
|
frame_data = np.array_split(list(range(0, len(self.data_df))), self.core_cnt)
|
|
194
213
|
frame_data = [(i, x) for i, x in enumerate(frame_data)]
|
|
195
|
-
print(f"Creating gantt, multiprocessing (chunksize: {(self.multiprocess_chunksize)}, cores: {self.core_cnt})...")
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
print(f'Batch {result+1/self.core_cnt} complete...')
|
|
214
|
-
pool.terminate()
|
|
215
|
-
pool.join()
|
|
214
|
+
print(f"[{get_current_time()}] Creating gantt, multiprocessing (chunksize: {(self.multiprocess_chunksize)}, cores: {self.core_cnt})...")
|
|
215
|
+
constants = functools.partial(gantt_creator_mp,
|
|
216
|
+
video_setting=self.video_setting,
|
|
217
|
+
frame_setting=self.frame_setting,
|
|
218
|
+
video_save_dir=self.temp_folder,
|
|
219
|
+
frame_folder_dir=self.save_frame_folder_dir,
|
|
220
|
+
bouts_df=self.bouts_df,
|
|
221
|
+
clf_names=self.clf_names,
|
|
222
|
+
fps=self.fps,
|
|
223
|
+
width=self.width,
|
|
224
|
+
height=self.height,
|
|
225
|
+
font_size=self.font_size,
|
|
226
|
+
font_rotation=self.font_rotation,
|
|
227
|
+
video_name=self.video_name,
|
|
228
|
+
palette=self.clr_lst,
|
|
229
|
+
hhmmss=self.hhmmss)
|
|
230
|
+
for cnt, result in enumerate(self.pool.imap(constants, frame_data, chunksize=self.multiprocess_chunksize)):
|
|
231
|
+
print(f'[{get_current_time()}] Batch {result+1}/{self.core_cnt} complete...')
|
|
216
232
|
if self.video_setting:
|
|
217
|
-
print(f"Joining {self.video_name} multiprocessed video...")
|
|
233
|
+
print(f"[{get_current_time()}] Joining {self.video_name} multiprocessed video...")
|
|
218
234
|
concatenate_videos_in_folder(in_folder=self.temp_folder, save_path=self.save_video_path)
|
|
219
235
|
video_timer.stop_timer()
|
|
220
236
|
print(f"Gantt video {self.video_name} complete (elapsed time: {video_timer.elapsed_time_str}s) ...")
|
|
221
237
|
|
|
238
|
+
terminate_cpu_pool(pool=self.pool, force=False, source=self.__class__.__name__)
|
|
222
239
|
self.timer.stop_timer()
|
|
223
240
|
stdout_success(msg=f"Gantt visualizations for {len(self.data_paths)} videos created in {self.gantt_plot_dir} directory", elapsed_time=self.timer.elapsed_time_str)
|
|
224
241
|
|
|
@@ -235,7 +252,18 @@ class GanttCreatorMultiprocess(ConfigReader, PlottingMixin):
|
|
|
235
252
|
# font_rotation= 45)
|
|
236
253
|
# test.run()
|
|
237
254
|
|
|
238
|
-
|
|
255
|
+
if __name__ == "__main__":
|
|
256
|
+
test = GanttCreatorMultiprocess(config_path=r"D:\troubleshooting\maplight_ri\project_folder\project_config.ini",
|
|
257
|
+
frame_setting=False,
|
|
258
|
+
video_setting=True,
|
|
259
|
+
data_paths=r"D:\troubleshooting\maplight_ri\project_folder\csv\machine_results\Trial_1_C24_D1_1.csv",
|
|
260
|
+
last_frm_setting=False,
|
|
261
|
+
width=640,
|
|
262
|
+
height= 480,
|
|
263
|
+
font_size=10,
|
|
264
|
+
font_rotation= 45,
|
|
265
|
+
core_cnt=16)
|
|
266
|
+
test.run()
|
|
239
267
|
|
|
240
268
|
|
|
241
269
|
# test = GanttCreatorMultiprocess(config_path='/Users/simon/Desktop/envs/simba/troubleshooting/RAT_NOR/project_folder/project_config.ini',
|