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.
Files changed (53) hide show
  1. simba/SimBA.py +2 -2
  2. simba/assets/icons/frames_2.png +0 -0
  3. simba/data_processors/agg_clf_counter_mp.py +52 -53
  4. simba/data_processors/cuda/image.py +3 -1
  5. simba/data_processors/cue_light_analyzer.py +5 -9
  6. simba/mixins/geometry_mixin.py +14 -28
  7. simba/mixins/image_mixin.py +10 -14
  8. simba/mixins/train_model_mixin.py +2 -2
  9. simba/plotting/ROI_feature_visualizer_mp.py +3 -5
  10. simba/plotting/clf_validator_mp.py +4 -5
  11. simba/plotting/cue_light_visualizer.py +6 -7
  12. simba/plotting/directing_animals_visualizer_mp.py +2 -3
  13. simba/plotting/distance_plotter_mp.py +378 -378
  14. simba/plotting/frame_mergerer_ffmpeg.py +137 -137
  15. simba/plotting/gantt_creator_mp.py +59 -31
  16. simba/plotting/geometry_plotter.py +270 -272
  17. simba/plotting/heat_mapper_clf_mp.py +2 -4
  18. simba/plotting/heat_mapper_location_mp.py +2 -2
  19. simba/plotting/light_dark_box_plotter.py +2 -2
  20. simba/plotting/path_plotter_mp.py +26 -29
  21. simba/plotting/plot_clf_results_mp.py +455 -454
  22. simba/plotting/pose_plotter_mp.py +27 -32
  23. simba/plotting/probability_plot_creator_mp.py +288 -288
  24. simba/plotting/roi_plotter_mp.py +29 -30
  25. simba/plotting/single_run_model_validation_video_mp.py +427 -427
  26. simba/plotting/spontaneous_alternation_plotter.py +2 -3
  27. simba/plotting/yolo_pose_track_visualizer.py +31 -27
  28. simba/plotting/yolo_pose_visualizer.py +32 -34
  29. simba/plotting/yolo_seg_visualizer.py +2 -3
  30. simba/roi_tools/roi_aggregate_stats_mp.py +4 -3
  31. simba/roi_tools/roi_clf_calculator_mp.py +3 -3
  32. simba/sandbox/cuda/egocentric_rotator.py +374 -0
  33. simba/sandbox/get_cpu_pool.py +5 -0
  34. simba/ui/pop_ups/clf_add_remove_print_pop_up.py +3 -1
  35. simba/ui/pop_ups/egocentric_alignment_pop_up.py +6 -3
  36. simba/ui/pop_ups/multiple_videos_to_frames_popup.py +10 -11
  37. simba/ui/pop_ups/single_video_to_frames_popup.py +10 -10
  38. simba/ui/pop_ups/video_processing_pop_up.py +63 -63
  39. simba/ui/tkinter_functions.py +7 -1
  40. simba/utils/data.py +89 -12
  41. simba/utils/enums.py +1 -0
  42. simba/utils/printing.py +9 -8
  43. simba/utils/read_write.py +3726 -3721
  44. simba/video_processors/clahe_ui.py +65 -22
  45. simba/video_processors/egocentric_video_rotator.py +6 -9
  46. simba/video_processors/video_processing.py +21 -10
  47. simba/video_processors/videos_to_frames.py +3 -2
  48. {simba_uw_tf_dev-4.6.1.dist-info → simba_uw_tf_dev-4.6.3.dist-info}/METADATA +1 -1
  49. {simba_uw_tf_dev-4.6.1.dist-info → simba_uw_tf_dev-4.6.3.dist-info}/RECORD +53 -50
  50. {simba_uw_tf_dev-4.6.1.dist-info → simba_uw_tf_dev-4.6.3.dist-info}/LICENSE +0 -0
  51. {simba_uw_tf_dev-4.6.1.dist-info → simba_uw_tf_dev-4.6.3.dist-info}/WHEEL +0 -0
  52. {simba_uw_tf_dev-4.6.1.dist-info → simba_uw_tf_dev-4.6.3.dist-info}/entry_points.txt +0 -0
  53. {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
- check_valid_lst, check_valid_boolean)
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
- print(f"Gantt frame created: {current_frm + 1}, Video: {video_name}, Processing core: {batch_id + 1}")
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: Optional[int] = -1,
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
- with multiprocessing.Pool(self.core_cnt, maxtasksperchild=self.maxtasksperchild) as pool:
197
- constants = functools.partial(gantt_creator_mp,
198
- video_setting=self.video_setting,
199
- frame_setting=self.frame_setting,
200
- video_save_dir=self.temp_folder,
201
- frame_folder_dir=self.save_frame_folder_dir,
202
- bouts_df=self.bouts_df,
203
- clf_names=self.clf_names,
204
- fps=self.fps,
205
- width=self.width,
206
- height=self.height,
207
- font_size=self.font_size,
208
- font_rotation=self.font_rotation,
209
- video_name=self.video_name,
210
- palette=self.clr_lst,
211
- hhmmss=self.hhmmss)
212
- for cnt, result in enumerate(pool.imap(constants, frame_data, chunksize=self.multiprocess_chunksize)):
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',