simba-uw-tf-dev 4.6.6__py3-none-any.whl → 4.6.7__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 (45) hide show
  1. simba/data_processors/blob_location_computer.py +1 -1
  2. simba/data_processors/cuda/image.py +12 -8
  3. simba/data_processors/cuda/statistics.py +57 -18
  4. simba/data_processors/cuda/timeseries.py +1 -1
  5. simba/data_processors/egocentric_aligner.py +1 -1
  6. simba/feature_extractors/feature_subsets.py +2 -2
  7. simba/feature_extractors/straub_tail_analyzer.py +4 -4
  8. simba/labelling/standard_labeller.py +1 -1
  9. simba/mixins/geometry_mixin.py +8 -8
  10. simba/mixins/image_mixin.py +14 -14
  11. simba/mixins/statistics_mixin.py +39 -9
  12. simba/mixins/timeseries_features_mixin.py +1 -1
  13. simba/mixins/train_model_mixin.py +65 -27
  14. simba/model/inference_batch.py +1 -1
  15. simba/model/yolo_seg_inference.py +3 -3
  16. simba/plotting/heat_mapper_clf_mp.py +2 -2
  17. simba/pose_importers/simba_blob_importer.py +3 -3
  18. simba/roi_tools/roi_aggregate_stats_mp.py +1 -1
  19. simba/roi_tools/roi_clf_calculator_mp.py +1 -1
  20. simba/sandbox/analyze_runtimes.py +30 -30
  21. simba/sandbox/test_directionality.py +47 -47
  22. simba/sandbox/test_nonstatic_directionality.py +27 -27
  23. simba/sandbox/test_pycharm_cuda.py +51 -51
  24. simba/sandbox/test_simba_install.py +41 -41
  25. simba/sandbox/test_static_directionality.py +26 -26
  26. simba/sandbox/test_static_directionality_2d.py +26 -26
  27. simba/sandbox/verify_env.py +42 -42
  28. simba/third_party_label_appenders/transform/coco_keypoints_to_yolo.py +3 -3
  29. simba/third_party_label_appenders/transform/coco_keypoints_to_yolo_bbox.py +2 -2
  30. simba/utils/custom_feature_extractor.py +1 -1
  31. simba/utils/data.py +2 -2
  32. simba/utils/read_write.py +32 -18
  33. simba/utils/yolo.py +10 -1
  34. simba/video_processors/blob_tracking_executor.py +2 -2
  35. simba/video_processors/clahe_ui.py +1 -1
  36. simba/video_processors/egocentric_video_rotator.py +3 -3
  37. simba/video_processors/multi_cropper.py +1 -1
  38. simba/video_processors/video_processing.py +26 -9
  39. simba/video_processors/videos_to_frames.py +2 -2
  40. {simba_uw_tf_dev-4.6.6.dist-info → simba_uw_tf_dev-4.6.7.dist-info}/METADATA +3 -2
  41. {simba_uw_tf_dev-4.6.6.dist-info → simba_uw_tf_dev-4.6.7.dist-info}/RECORD +45 -45
  42. {simba_uw_tf_dev-4.6.6.dist-info → simba_uw_tf_dev-4.6.7.dist-info}/LICENSE +0 -0
  43. {simba_uw_tf_dev-4.6.6.dist-info → simba_uw_tf_dev-4.6.7.dist-info}/WHEEL +0 -0
  44. {simba_uw_tf_dev-4.6.6.dist-info → simba_uw_tf_dev-4.6.7.dist-info}/entry_points.txt +0 -0
  45. {simba_uw_tf_dev-4.6.6.dist-info → simba_uw_tf_dev-4.6.7.dist-info}/top_level.txt +0 -0
@@ -1,41 +1,41 @@
1
- """Test SimBA installation in conda environment"""
2
- import sys
3
- print(f"Python: {sys.executable}")
4
-
5
- try:
6
- import simba
7
- print("✓ SimBA imported successfully!")
8
- except Exception as e:
9
- print(f"✗ Error importing SimBA: {e}")
10
- import traceback
11
- traceback.print_exc()
12
- sys.exit(1)
13
-
14
- try:
15
- from simba.data_processors.cuda.geometry import is_inside_rectangle
16
- print("✓ CUDA geometry functions imported!")
17
- except Exception as e:
18
- print(f"✗ Error importing CUDA functions: {e}")
19
- import traceback
20
- traceback.print_exc()
21
- sys.exit(1)
22
-
23
- try:
24
- import cupy as cp
25
- import numpy as np
26
- print(f"✓ CuPy {cp.__version__} available")
27
-
28
- # Quick test
29
- test_points = np.array([[150, 150], [300, 300], [50, 50]], dtype=np.int32)
30
- test_rect = np.array([[100, 100], [400, 400]], dtype=np.int32)
31
- result = is_inside_rectangle(x=test_points, y=test_rect)
32
- print(f"✓ CUDA function test passed: {result}")
33
- except Exception as e:
34
- print(f"✗ Error testing CUDA: {e}")
35
- import traceback
36
- traceback.print_exc()
37
- sys.exit(1)
38
-
39
- print("\n" + "="*50)
40
- print("All tests passed! SimBA is ready to use.")
41
- print("="*50)
1
+ """Test SimBA installation in conda environment"""
2
+ import sys
3
+ print(f"Python: {sys.executable}")
4
+
5
+ try:
6
+ import simba
7
+ print("✓ SimBA imported successfully!")
8
+ except Exception as e:
9
+ print(f"✗ Error importing SimBA: {e}")
10
+ import traceback
11
+ traceback.print_exc()
12
+ sys.exit(1)
13
+
14
+ try:
15
+ from simba.data_processors.cuda.geometry import is_inside_rectangle
16
+ print("✓ CUDA geometry functions imported!")
17
+ except Exception as e:
18
+ print(f"✗ Error importing CUDA functions: {e}")
19
+ import traceback
20
+ traceback.print_exc()
21
+ sys.exit(1)
22
+
23
+ try:
24
+ import cupy as cp
25
+ import numpy as np
26
+ print(f"✓ CuPy {cp.__version__} available")
27
+
28
+ # Quick test
29
+ test_points = np.array([[150, 150], [300, 300], [50, 50]], dtype=np.int32)
30
+ test_rect = np.array([[100, 100], [400, 400]], dtype=np.int32)
31
+ result = is_inside_rectangle(x=test_points, y=test_rect)
32
+ print(f"✓ CUDA function test passed: {result}")
33
+ except Exception as e:
34
+ print(f"✗ Error testing CUDA: {e}")
35
+ import traceback
36
+ traceback.print_exc()
37
+ sys.exit(1)
38
+
39
+ print("\n" + "="*50)
40
+ print("All tests passed! SimBA is ready to use.")
41
+ print("="*50)
@@ -1,26 +1,26 @@
1
- """Test directionality_to_static_targets function"""
2
- import numpy as np
3
- from simba.data_processors.cuda.geometry import directionality_to_static_targets
4
-
5
- print("Testing directionality_to_static_targets...")
6
-
7
- left_ear = np.random.randint(0, 500, (10, 2)).astype(np.int32)
8
- right_ear = np.random.randint(0, 500, (10, 2)).astype(np.int32)
9
- nose = np.random.randint(0, 500, (10, 2)).astype(np.int32)
10
- target = np.array([250, 250], dtype=np.int32)
11
-
12
- print(f"target shape: {target.shape}, dtype: {target.dtype}")
13
-
14
- try:
15
- result = directionality_to_static_targets(
16
- left_ear=left_ear,
17
- right_ear=right_ear,
18
- nose=nose,
19
- target=target
20
- )
21
- print(f"✓ SUCCESS! Result shape: {result.shape}")
22
- print(f"Result:\n{result}")
23
- except Exception as e:
24
- print(f"✗ Error: {e}")
25
- import traceback
26
- traceback.print_exc()
1
+ """Test directionality_to_static_targets function"""
2
+ import numpy as np
3
+ from simba.data_processors.cuda.geometry import directionality_to_static_targets
4
+
5
+ print("Testing directionality_to_static_targets...")
6
+
7
+ left_ear = np.random.randint(0, 500, (10, 2)).astype(np.int32)
8
+ right_ear = np.random.randint(0, 500, (10, 2)).astype(np.int32)
9
+ nose = np.random.randint(0, 500, (10, 2)).astype(np.int32)
10
+ target = np.array([250, 250], dtype=np.int32)
11
+
12
+ print(f"target shape: {target.shape}, dtype: {target.dtype}")
13
+
14
+ try:
15
+ result = directionality_to_static_targets(
16
+ left_ear=left_ear,
17
+ right_ear=right_ear,
18
+ nose=nose,
19
+ target=target
20
+ )
21
+ print(f"✓ SUCCESS! Result shape: {result.shape}")
22
+ print(f"Result:\n{result}")
23
+ except Exception as e:
24
+ print(f"✗ Error: {e}")
25
+ import traceback
26
+ traceback.print_exc()
@@ -1,26 +1,26 @@
1
- """Test directionality_to_static_targets with correct 1D target"""
2
- import numpy as np
3
- from simba.data_processors.cuda.geometry import directionality_to_static_targets
4
-
5
- print("Testing directionality_to_static_targets with 1D target (correct)...")
6
-
7
- left_ear = np.random.randint(0, 500, (100, 2)).astype(np.int32)
8
- right_ear = np.random.randint(0, 500, (100, 2)).astype(np.int32)
9
- nose = np.random.randint(0, 500, (100, 2)).astype(np.int32)
10
- target = np.array([250, 250], dtype=np.int32) # 1D array for static target
11
-
12
- print(f"target shape: {target.shape}, dtype: {target.dtype}")
13
-
14
- try:
15
- result = directionality_to_static_targets(
16
- left_ear=left_ear,
17
- right_ear=right_ear,
18
- nose=nose,
19
- target=target
20
- )
21
- print(f"✓ SUCCESS! Result shape: {result.shape}")
22
- print(f"First 5 results:\n{result[:5]}")
23
- except Exception as e:
24
- print(f"✗ Error: {e}")
25
- import traceback
26
- traceback.print_exc()
1
+ """Test directionality_to_static_targets with correct 1D target"""
2
+ import numpy as np
3
+ from simba.data_processors.cuda.geometry import directionality_to_static_targets
4
+
5
+ print("Testing directionality_to_static_targets with 1D target (correct)...")
6
+
7
+ left_ear = np.random.randint(0, 500, (100, 2)).astype(np.int32)
8
+ right_ear = np.random.randint(0, 500, (100, 2)).astype(np.int32)
9
+ nose = np.random.randint(0, 500, (100, 2)).astype(np.int32)
10
+ target = np.array([250, 250], dtype=np.int32) # 1D array for static target
11
+
12
+ print(f"target shape: {target.shape}, dtype: {target.dtype}")
13
+
14
+ try:
15
+ result = directionality_to_static_targets(
16
+ left_ear=left_ear,
17
+ right_ear=right_ear,
18
+ nose=nose,
19
+ target=target
20
+ )
21
+ print(f"✓ SUCCESS! Result shape: {result.shape}")
22
+ print(f"First 5 results:\n{result[:5]}")
23
+ except Exception as e:
24
+ print(f"✗ Error: {e}")
25
+ import traceback
26
+ traceback.print_exc()
@@ -1,42 +1,42 @@
1
- """Verify CUDA environment is properly configured"""
2
- from numba import cuda
3
- import cupy as cp
4
- import numba
5
-
6
- print("="*60)
7
- print("CUDA Environment Verification")
8
- print("="*60)
9
- print(f"Numba version: {numba.__version__}")
10
- print(f"CuPy version: {cp.__version__}")
11
- print(f"CUDA available: {cuda.is_available()}")
12
- if cuda.is_available():
13
- print(f"CUDA devices: {len(cuda.gpus)}")
14
- for i, gpu in enumerate(cuda.gpus):
15
- print(f" GPU {i}: {gpu}")
16
-
17
- # Test the function
18
- print("\n" + "="*60)
19
- print("Testing directionality_to_nonstatic_target...")
20
- try:
21
- from simba.data_processors.cuda.geometry import directionality_to_nonstatic_target
22
- import numpy as np
23
-
24
- left_ear = np.random.randint(0, 500, (10, 2)).astype(np.int32)
25
- right_ear = np.random.randint(0, 500, (10, 2)).astype(np.int32)
26
- nose = np.random.randint(0, 500, (10, 2)).astype(np.int32)
27
- target = np.random.randint(0, 500, (10, 2)).astype(np.int32)
28
-
29
- result = directionality_to_nonstatic_target(
30
- left_ear=left_ear,
31
- right_ear=right_ear,
32
- nose=nose,
33
- target=target
34
- )
35
- print(f"✓ Function works! Result shape: {result.shape}")
36
- except Exception as e:
37
- print(f"✗ Error: {e}")
38
- import traceback
39
- traceback.print_exc()
40
-
41
- print("\n" + "="*60)
42
- print("Environment is ready!")
1
+ """Verify CUDA environment is properly configured"""
2
+ from numba import cuda
3
+ import cupy as cp
4
+ import numba
5
+
6
+ print("="*60)
7
+ print("CUDA Environment Verification")
8
+ print("="*60)
9
+ print(f"Numba version: {numba.__version__}")
10
+ print(f"CuPy version: {cp.__version__}")
11
+ print(f"CUDA available: {cuda.is_available()}")
12
+ if cuda.is_available():
13
+ print(f"CUDA devices: {len(cuda.gpus)}")
14
+ for i, gpu in enumerate(cuda.gpus):
15
+ print(f" GPU {i}: {gpu}")
16
+
17
+ # Test the function
18
+ print("\n" + "="*60)
19
+ print("Testing directionality_to_nonstatic_target...")
20
+ try:
21
+ from simba.data_processors.cuda.geometry import directionality_to_nonstatic_target
22
+ import numpy as np
23
+
24
+ left_ear = np.random.randint(0, 500, (10, 2)).astype(np.int32)
25
+ right_ear = np.random.randint(0, 500, (10, 2)).astype(np.int32)
26
+ nose = np.random.randint(0, 500, (10, 2)).astype(np.int32)
27
+ target = np.random.randint(0, 500, (10, 2)).astype(np.int32)
28
+
29
+ result = directionality_to_nonstatic_target(
30
+ left_ear=left_ear,
31
+ right_ear=right_ear,
32
+ nose=nose,
33
+ target=target
34
+ )
35
+ print(f"✓ Function works! Result shape: {result.shape}")
36
+ except Exception as e:
37
+ print(f"✗ Error: {e}")
38
+ import traceback
39
+ traceback.print_exc()
40
+
41
+ print("\n" + "="*60)
42
+ print("Environment is ready!")
@@ -54,15 +54,15 @@ class COCOKeypoints2Yolo:
54
54
  :return: None
55
55
 
56
56
  :example:
57
- >>> runner = COCOKeypoints2Yolo(coco_path=r"D:\cvat_annotations\frames\coco_keypoints_1\s1\annotations\s1.json", img_dir=r"D:\cvat_annotations\frames\simon", save_dir=r"D:\cvat_annotations\frames\yolo_keypoints", clahe=True)
57
+ >>> runner = COCOKeypoints2Yolo(coco_path=r"D:/cvat_annotations/frames/coco_keypoints_1/s1/annotations/s1.json", img_dir=r"D:/cvat_annotations/frames/simon", save_dir=r"D:/cvat_annotations/frames/yolo_keypoints", clahe=True)
58
58
  >>> runner.run()
59
59
 
60
60
  :example II:
61
- >>> runner = COCOKeypoints2Yolo(coco_path=r"D:\cvat_annotations\frames\coco_keypoints_1\merged.json", img_dir=r"D:\cvat_annotations\frames", save_dir=r"D:\cvat_annotations\frames\yolo", clahe=False)
61
+ >>> runner = COCOKeypoints2Yolo(coco_path=r"D:/cvat_annotations/frames/coco_keypoints_1/merged.json", img_dir=r"D:/cvat_annotations/frames", save_dir=r"D:/cvat_annotations/frames/yolo", clahe=False)
62
62
  >>> runner.run()
63
63
 
64
64
  :example III:
65
- >>> runner = COCOKeypoints2Yolo(coco_path=r"E:\netholabs_videos\mosaics\subset\to_annotate\2d_mosaic_batch_1.json", img_dir=r"E:\netholabs_videos\mosaics\subset\to_annotate", save_dir=r"E:\netholabs_videos\mosaics\yolo_mdl", clahe=False)
65
+ >>> runner = COCOKeypoints2Yolo(coco_path=r"E:/netholabs_videos/mosaics/subset/to_annotate/2d_mosaic_batch_1.json", img_dir=r"E:/netholabs_videos/mosaics/subset/to_annotate", save_dir=r"E:/netholabs_videos/mosaics/yolo_mdl", clahe=False)
66
66
  >>> runner.run()
67
67
 
68
68
  :references:
@@ -58,11 +58,11 @@ class COCOKeypoints2YoloBbox:
58
58
  :return: None
59
59
 
60
60
  :example:
61
- >>> runner = COCOKeypoints2Yolo(coco_path=r"D:\cvat_annotations\frames\coco_keypoints_1\s1\annotations\s1.json", img_dir=r"D:\cvat_annotations\frames\simon", save_dir=r"D:\cvat_annotations\frames\yolo_keypoints", clahe=True)
61
+ >>> runner = COCOKeypoints2YoloBbox(coco_path=r"D:/cvat_annotations/frames/coco_keypoints_1/s1/annotations/s1.json", img_dir=r"D:/cvat_annotations/frames/simon", save_dir=r"D:/cvat_annotations/frames/yolo_keypoints", clahe=True)
62
62
  >>> runner.run()
63
63
 
64
64
  :example II:
65
- >>> runner = COCOKeypoints2Yolo(coco_path=r"D:\cvat_annotations\frames\coco_keypoints_1\merged.json", img_dir=r"D:\cvat_annotations\frames", save_dir=r"D:\cvat_annotations\frames\yolo", clahe=False)
65
+ >>> runner = COCOKeypoints2YoloBbox(coco_path=r"D:/cvat_annotations/frames/coco_keypoints_1/merged.json", img_dir=r"D:/cvat_annotations/frames", save_dir=r"D:/cvat_annotations/frames/yolo", clahe=False)
66
66
  >>> runner.run()
67
67
 
68
68
  :references:
@@ -30,7 +30,7 @@ class CustomFeatureExtractor(ConfigReader):
30
30
  4. Handle cases of multiple classes and missing configuration arguments.
31
31
  5. Invokes the feature extraction process if conditions are met.
32
32
 
33
- .. notes::
33
+ .. note::
34
34
 
35
35
  `Tutorial <https://github.com/sgoldenlab/simba/blob/master/docs/extractFeatures.md>`_.
36
36
 
simba/utils/data.py CHANGED
@@ -1785,8 +1785,8 @@ def fft_lowpass_filter(data: np.ndarray, cut_off: float = 0.1) -> np.ndarray:
1785
1785
 
1786
1786
  :example:
1787
1787
  >>> from simba.utils.read_write import read_df
1788
- >>> IN_PATH = r"C:\troubleshooting\RAT_NOR\project_folder\csv\outlier_corrected_movement_location\2022-06-20_NOB_DOT_4.csv"
1789
- >>> OUT_PATH = r"C:\troubleshooting\RAT_NOR\project_folder\csv\outlier_corrected_movement_location\2022-06-20_NOB_DOT_4_filtered.csv"
1788
+ >>> IN_PATH = r"C:/troubleshooting/RAT_NOR/project_folder/csv/outlier_corrected_movement_location/2022-06-20_NOB_DOT_4.csv"
1789
+ >>> OUT_PATH = r"C:/troubleshooting/RAT_NOR/project_folder/csv/outlier_corrected_movement_location/2022-06-20_NOB_DOT_4_filtered.csv"
1790
1790
  >>> df = read_df(file_path=IN_PATH)
1791
1791
  >>> data = df.values
1792
1792
  >>> x = fft_lowpass_filter(data=data, cut_off=0.1)
simba/utils/read_write.py CHANGED
@@ -97,13 +97,20 @@ def read_df(file_path: Union[str, os.PathLike],
97
97
  .. note::
98
98
  For improved runtime, defaults to :external:py:meth:`pyarrow.csv.write_cs` if file type is ``csv``.
99
99
 
100
- :parameter str file_path: Path to data file
101
- :parameter str file_type: Type of data. OPTIONS: 'parquet', 'csv', 'pickle'.
102
- :parameter Optional[bool]: If the input file has an initial index column. Default: True.
103
- :parameter Optional[List[str]] remove_columns: If not None, then remove columns in lits.
104
- :parameter Optional[List[str]] usecols: If not None, then keep columns in list.
105
- :parameter bool check_multiindex: check file is multi-index headers. Default: False.
106
- :parameter int multi_index_headers_to_keep: If reading multi-index file, and we want to keep one of the dropped multi-index levels as the header in the output file, specify the index of the multiindex hader as int.
100
+ .. csv-table::
101
+ :header: EXPECTED RUNTIMES
102
+ :file: ../../docs/tables/read_df.csv
103
+ :widths: 10, 45, 45
104
+ :align: center
105
+ :header-rows: 1
106
+
107
+ :param str file_path: Path to data file
108
+ :param str file_type: Type of data. OPTIONS: 'parquet', 'csv', 'pickle'.
109
+ :param Optional[bool]: If the input file has an initial index column. Default: True.
110
+ :param Optional[List[str]] remove_columns: If not None, then remove columns in lits.
111
+ :param Optional[List[str]] usecols: If not None, then keep columns in list.
112
+ :param bool check_multiindex: check file is multi-index headers. Default: False.
113
+ :param int multi_index_headers_to_keep: If reading multi-index file, and we want to keep one of the dropped multi-index levels as the header in the output file, specify the index of the multiindex hader as int.
107
114
  :return: Table data in pd.DataFrame format.
108
115
  :rtype: pd.DataFrame
109
116
 
@@ -207,11 +214,18 @@ def write_df(df: pd.DataFrame,
207
214
  .. note::
208
215
  For improved runtime, defaults to ``pyarrow.csv`` if file_type == ``csv``.
209
216
 
210
- :parameter pd.DataFrame df: Pandas dataframe to save to disk.
211
- :parameter str file_type: Type of data. OPTIONS: ``parquet``, ``csv``, ``pickle``.
212
- :parameter str save_path: Location where to store the data.
213
- :parameter bool check_multiindex: check if input file is multi-index headers. Default: False.
214
- :parameter bool verbose: Prints message on completion. Default: False.
217
+ .. csv-table::
218
+ :header: EXPECTED RUNTIMES
219
+ :file: ../../docs/tables/write_df.csv
220
+ :widths: 10, 45, 45
221
+ :align: center
222
+ :header-rows: 1
223
+
224
+ :param pd.DataFrame df: Pandas dataframe to save to disk.
225
+ :param str file_type: Type of data. OPTIONS: ``parquet``, ``csv``, ``pickle``.
226
+ :param str save_path: Location where to store the data.
227
+ :param bool check_multiindex: check if input file is multi-index headers. Default: False.
228
+ :param bool verbose: Prints message on completion. Default: False.
215
229
 
216
230
  :example:
217
231
  >>> write_df(df=df, file_type='csv', save_path='project_folder/csv/input_csv/Video_1.csv')
@@ -1130,8 +1144,8 @@ def get_file_name_info_in_directory(directory: Union[str, os.PathLike], file_typ
1130
1144
  :return dict: All found files as values and file base names as keys.
1131
1145
 
1132
1146
  :example:
1133
- >>> get_file_name_info_in_directory(directory='C:\project_folder\csv\machine_results', file_type='csv')
1134
- >>> {'Video_1': 'C:\project_folder\csv\machine_results\Video_1'}
1147
+ >>> get_file_name_info_in_directory(directory='C:/project_folder/csv/machine_results', file_type='csv')
1148
+ >>> {'Video_1': 'C:/project_folder/csv/machine_results/Video_1'}
1135
1149
  """
1136
1150
 
1137
1151
  results = {}
@@ -2630,7 +2644,7 @@ def bento_file_reader(file_path: Union[str, os.PathLike],
2630
2644
  :rtype: Dict[str, pd.DataFrame]
2631
2645
 
2632
2646
  :example:
2633
- >>> bento_file_reader(file_path=r"C:\troubleshooting\bento_test\bento_files\20240812_crumpling3.annot")
2647
+ >>> bento_file_reader(file_path=r"C:/troubleshooting/bento_test/bento_files/20240812_crumpling3.annot")
2634
2648
  """
2635
2649
 
2636
2650
  def _orient_columns_melt(df: pd.DataFrame) -> pd.DataFrame:
@@ -2953,7 +2967,7 @@ def labelme_to_dlc(labelme_dir: Union[str, os.PathLike],
2953
2967
  :return: None
2954
2968
 
2955
2969
  :example:
2956
- >>> labelme_dir = r'D:\ts_annotations'
2970
+ >>> labelme_dir = r'D:/ts_annotations'
2957
2971
  >>> labelme_to_dlc(labelme_dir=labelme_dir)
2958
2972
  """
2959
2973
 
@@ -3597,8 +3611,8 @@ def osf_download(project_id: str, save_dir: Union[str, os.PathLike], storage: st
3597
3611
  :param bool overwrite: If True, overwrite existing files. If False, skip existing files (default: False).
3598
3612
 
3599
3613
  :example:
3600
- >>> osf_download(project_id="7fgwn", save_dir=r'E:\rgb_white_vs_black_imgs')
3601
- >>> osf_download(project_id="kym42", save_dir=r'E:\crim13_imgs', overwrite=True)
3614
+ >>> osf_download(project_id="7fgwn", save_dir=r'E:/rgb_white_vs_black_imgs')
3615
+ >>> osf_download(project_id="kym42", save_dir=r'E:/crim13_imgs', overwrite=True)
3602
3616
  """
3603
3617
 
3604
3618
  _ = get_pkg_version(pkg='osfclient', raise_error=True)
simba/utils/yolo.py CHANGED
@@ -47,6 +47,9 @@ def fit_yolo(weights_path: Union[str, os.PathLike],
47
47
  `Download initial weights <https://huggingface.co/Ultralytics>`__.
48
48
  `Example model_yaml <https://github.com/sgoldenlab/simba/blob/master/misc/ex_yolo_model.yaml>`__.
49
49
 
50
+ .. seealso::
51
+ For the recommended wrapper class with parameter validation, see :class:`simba.model.yolo_fit.FitYolo`.
52
+
50
53
  :param initial_weights: Path to the pre-trained YOLO model weights (usually a `.pt` file). Example weights can be found [here](https://huggingface.co/Ultralytics).
51
54
  :param model_yaml: YAML file containing paths to the training, validation, and testing datasets and the object class mappings. Example YAML file can be found [here](https://github.com/sgoldenlab/simba/blob/master/misc/ex_yolo_model.yaml).
52
55
  :param save_path: Directory path where the trained model, logs, and results will be saved.
@@ -55,7 +58,7 @@ def fit_yolo(weights_path: Union[str, os.PathLike],
55
58
  :return: None. The trained model and associated training logs are saved in the specified `project_path`.
56
59
 
57
60
  :example:
58
- >>> fit_yolo(initial_weights=r"C:\troubleshooting\coco_data\weights\yolov8n-obb.pt", data=r"C:\troubleshooting\coco_data\model.yaml", save_path=r"C:\troubleshooting\coco_data\mdl", batch=16)
61
+ >>> fit_yolo(initial_weights=r"C:/troubleshooting/coco_data/weights/yolov8n-obb.pt", data=r"C:/troubleshooting/coco_data/model.yaml", save_path=r"C:/troubleshooting/coco_data/mdl", batch=16)
59
62
  """
60
63
 
61
64
  if not _is_cuda_available()[0]:
@@ -83,6 +86,9 @@ def load_yolo_model(weights_path: Union[str, os.PathLike],
83
86
  """
84
87
  Load a YOLO model.
85
88
 
89
+ .. seealso::
90
+ For recommended wrapper classes that use this function, see :class:`simba.model.yolo_fit.FitYolo`, :class:`simba.model.yolo_inference.YoloInference`, :class:`simba.model.yolo_pose_inference.YOLOPoseInference`, :class:`simba.model.yolo_seg_inference.YOLOSegmentationInference`, and :class:`simba.model.yolo_pose_track_inference.YOLOPoseTrackInference`.
91
+
86
92
  :param Union[str, os.PathLike] weights_path: Path to model weights (.pt, .engine, etc).
87
93
  :param bool verbose: Whether to print loading info.
88
94
  :param Optional[str] format: Export format, one of VALID_FORMATS or None to skip export.
@@ -169,6 +175,9 @@ def yolo_predict(model: YOLO,
169
175
  """
170
176
  Produce YOLO predictions.
171
177
 
178
+ .. seealso::
179
+ For recommended wrapper classes that use this function, see :class:`simba.model.yolo_inference.YoloInference`, :class:`simba.model.yolo_pose_inference.YOLOPoseInference`, and :class:`simba.model.yolo_seg_inference.YOLOSegmentationInference`.
180
+
172
181
  :param Union[str, os.PathLike] model: Loaded ultralytics.YOLO model. Returned by :func:`~simba.bounding_box_tools.yolo.model.load_yolo_model`.
173
182
  :param Union[str, os.PathLike, np.ndarray] source: Path to video, video stream, directory, image, or image as loaded array.
174
183
  :param bool half: Whether to use half precision (FP16) for inference to speed up processing.
@@ -87,9 +87,9 @@ class BlobTrackingExecutor():
87
87
  :param bool center: If True, compute center coordinates. Default: True.
88
88
 
89
89
  :example:
90
- >>> tracker = BlobTrackingExecutor(data=r"C:\troubleshooting\mitra\test\.temp\blob_definitions.pickle")
90
+ >>> tracker = BlobTrackingExecutor(data=r"C:/troubleshooting/mitra/test/.temp/blob_definitions.pickle")
91
91
  >>> tracker.run()
92
- >>> tracker = BlobTrackingExecutor(data=r"C:\troubleshooting\mitra\test\.temp\blob_definitions.pickle", batch_size=5000)
92
+ >>> tracker = BlobTrackingExecutor(data=r"C:/troubleshooting/mitra/test/.temp/blob_definitions.pickle", batch_size=5000)
93
93
  >>> tracker.run()
94
94
  """
95
95
 
@@ -29,7 +29,7 @@ def interactive_clahe_ui(data: Union[str, os.PathLike]) -> Tuple[float, int]:
29
29
  :return Tuple[float, int]: Tuple containing the chosen clip limit and tile size.
30
30
 
31
31
  :example:
32
- >>> video = cv2.imread(r"D:\EPM\sample_2\video_1.mp4")
32
+ >>> video = cv2.imread(r"D:/EPM/sample_2/video_1.mp4")
33
33
  >>> interactive_clahe_ui(data=video)
34
34
  """
35
35
  global original_img, font_size, x_spacer, y_spacer, txt
@@ -94,9 +94,9 @@ class EgocentricVideoRotator():
94
94
  :param Optional[Union[str, os.PathLike]] save_path: The location where to store the rotated video. If None, saves the video as the same dir as the input video with the `_rotated` suffix.
95
95
 
96
96
  :example:
97
- >>> DATA_PATH = "C:\501_MA142_Gi_Saline_0513.csv"
98
- >>> VIDEO_PATH = "C:\501_MA142_Gi_Saline_0513.mp4"
99
- >>> SAVE_PATH = "C:\501_MA142_Gi_Saline_0513_rotated.mp4"
97
+ >>> DATA_PATH = "C:/501_MA142_Gi_Saline_0513.csv"
98
+ >>> VIDEO_PATH = "C:/501_MA142_Gi_Saline_0513.mp4"
99
+ >>> SAVE_PATH = "C:/501_MA142_Gi_Saline_0513_rotated.mp4"
100
100
  >>> ANCHOR_LOC = np.array([250, 250])
101
101
 
102
102
  >>> df = read_df(file_path=DATA_PATH, file_type='csv')
@@ -49,7 +49,7 @@ class MultiCropper(object):
49
49
 
50
50
 
51
51
  :example:
52
- >>> cropper = MultiCropper(file_type='mp4', input_folder=r'C:\troubleshooting\mitra\test', output_folder=r'C:\troubleshooting\mitra\test\cropped', crop_cnt=2, gpu=True)
52
+ >>> cropper = MultiCropper(file_type='mp4', input_folder=r'C:/troubleshooting/mitra/test', output_folder=r'C:/troubleshooting/mitra/test/cropped', crop_cnt=2, gpu=True)
53
53
  >>> cropper.run()
54
54
  """
55
55
 
@@ -676,7 +676,7 @@ def change_single_video_fps(file_path: Union[str, os.PathLike],
676
676
 
677
677
  :param Union[str, os.PathLike] file_path: Path to video file
678
678
  :param Union[int, float] fps: FPS of the new video file.
679
- :param bool gpu: If True, use NVIDEA GPU codecs. Default False.
679
+ :param bool gpu: If True, use NVIDEA GPU codecs. Default False. GPU can provide significant speedup (3-4x faster) for FPS conversion, especially for longer videos.
680
680
  :param Optional[str] codec: Video codec to use. If None, automatically selects based on file extension (libvpx-vp9 for .webm, mpeg4 for .avi, libx264 for others). Default None.
681
681
  :param Optional[Union[str, os.PathLike]] save_path: Path where to save the converted video. If None, saves in the same directory as input file with ``_fps_{fps}`` suffix. Default None.
682
682
  :param Optional[int] quality: Video quality (CRF value). Lower values = higher quality. Range 0-52. Default 23.
@@ -702,7 +702,7 @@ def change_single_video_fps(file_path: Union[str, os.PathLike],
702
702
  else:
703
703
  check_if_dir_exists(in_dir=os.path.dirname(save_path), raise_error=True)
704
704
  quality = 23 if not check_int(name='quality', value=quality, min_value=0, max_value=52, raise_error=False)[0] else int(quality)
705
- if verbose: print(f"Converting the FPS to {fps} for video {file_name} ...")
705
+ if verbose: print(f"Converting the FPS {video_meta_data['fps']} -> {fps} for video {file_name} ...")
706
706
  if codec is None:
707
707
  if ext.lower() == '.webm':
708
708
  codec = 'libvpx-vp9'
@@ -713,10 +713,14 @@ def change_single_video_fps(file_path: Union[str, os.PathLike],
713
713
  if os.path.isfile(save_path):
714
714
  FileExistWarning(msg=f"Overwriting existing file at {save_path}...", source=change_single_video_fps.__name__,)
715
715
  if gpu:
716
- cmd = f'ffmpeg -hwaccel auto -c:v h264_cuvid -i "{file_path}" -vf "fps={fps}" -c:v h264_nvenc -rc vbr -cq {quality} -c:a copy "{save_path}" -loglevel error -stats -hide_banner -y'
717
- else:
716
+ cmd = f'ffmpeg -hwaccel auto -i "{file_path}" -vf "fps={fps}" -c:v h264_nvenc -preset p4 -cq {quality} -c:a copy "{save_path}" -loglevel error -stats -hide_banner -y'
717
+ result = subprocess.run(cmd, shell=True)
718
+ if result.returncode != 0:
719
+ if verbose: SimBAGPUError(msg=f'FPS convertion ({video_meta_data["fps"]}->{fps}) GPU for video {file_name} failed, using CPU instead...')
720
+ gpu = False
721
+ if not gpu:
718
722
  cmd = f'ffmpeg -i "{file_path}" -filter:v fps=fps={fps} -c:v {codec} -crf {quality} -c:a aac "{save_path}" -loglevel error -stats -hide_banner -y'
719
- subprocess.call(cmd, shell=True)
723
+ subprocess.call(cmd, shell=True)
720
724
  timer.stop_timer()
721
725
  if verbose: stdout_success(msg=f'SIMBA COMPLETE: FPS of video {file_name} changed from {str(video_meta_data["fps"])} to {str(fps)} and saved in directory {save_path}', elapsed_time=timer.elapsed_time_str, source=change_single_video_fps.__name__)
722
726
 
@@ -725,7 +729,8 @@ def change_fps_of_multiple_videos(path: Union[str, os.PathLike, List[Union[str,
725
729
  fps: int,
726
730
  quality: int = 23,
727
731
  save_dir: Optional[Union[str, os.PathLike]] = None,
728
- gpu: Optional[bool] = False) -> None:
732
+ gpu: Optional[bool] = False,
733
+ verbose: bool = True) -> None:
729
734
  """
730
735
  Change the fps of all video files in a folder. Results are stored in the same directory as in the input files with
731
736
  the suffix ``_fps_new_fps``.
@@ -735,6 +740,7 @@ def change_fps_of_multiple_videos(path: Union[str, os.PathLike, List[Union[str,
735
740
  :param int quality: Video quality (CRF value). Lower values = higher quality. Range 0-52. Default 23.
736
741
  :param Optional[Union[str, os.PathLike]] save_dir: If not None, then the directory where to store converted videos. If None, then stores the new videos in the same directory as the input video with the ``_fps_{fps}.file_extension`` suffix.
737
742
  :param Optional[bool] gpu: If True, use NVIDEA GPU codecs. Default False.
743
+ :param bool verbose: If True, prints conversion progress. Default True.
738
744
  :returns: None.
739
745
 
740
746
  :example:
@@ -764,7 +770,7 @@ def change_fps_of_multiple_videos(path: Union[str, os.PathLike, List[Union[str,
764
770
  video_meta_data = get_video_meta_data(video_path=file_path)
765
771
  if int(fps) == int(video_meta_data["fps"]):
766
772
  SameInputAndOutputWarning(msg=f"The new FPS ({fps}) is the same or lower than the original FPS ({video_meta_data['fps']}) for video {file_name}", source=change_fps_of_multiple_videos.__name__)
767
- print(f"Converting FPS from {video_meta_data['fps']} to {fps} for {file_name}...")
773
+ if verbose: print(f"Converting the FPS {video_meta_data['fps']} -> {fps} for video {file_name} ...")
768
774
  if save_dir is None:
769
775
  save_path = os.path.join(dir_name, file_name + f"_fps_{fps}{ext}")
770
776
  else:
@@ -772,15 +778,26 @@ def change_fps_of_multiple_videos(path: Union[str, os.PathLike, List[Union[str,
772
778
  if ext.lower() == '.webm': codec = 'libvpx-vp9'
773
779
  elif ext.lower() == '.avi': codec = 'mpeg4'
774
780
  else: codec = 'libx264'
781
+ if os.path.isfile(save_path):
782
+ FileExistWarning(msg=f"Overwriting existing file at {save_path}...", source=change_single_video_fps.__name__, )
783
+ if gpu:
784
+ cmd = f'ffmpeg -hwaccel auto -i "{file_path}" -vf "fps={fps}" -c:v h264_nvenc -preset p4 -cq {quality} -c:a copy "{save_path}" -loglevel error -stats -hide_banner -y'
785
+ result = subprocess.run(cmd, shell=True)
786
+ if result.returncode != 0:
787
+ if verbose: SimBAGPUError(msg=f'FPS convertion ({video_meta_data["fps"]}->{fps}) GPU for video {file_name} failed, using CPU instead...')
788
+ gpu = False
789
+ if not gpu:
790
+ cmd = f'ffmpeg -i "{file_path}" -filter:v fps=fps={fps} -c:v {codec} -crf {quality} -c:a aac "{save_path}" -loglevel error -stats -hide_banner -y'
791
+ subprocess.call(cmd, shell=True)
775
792
  if gpu:
776
793
  command = f'ffmpeg -hwaccel auto -c:v h264_cuvid -i "{file_path}" -vf "fps={fps}" -c:v h264_nvenc -rc vbr -cq {quality} -c:a copy "{save_path}" -loglevel error -stats -hide_banner -y'
777
794
  else:
778
795
  command = f'ffmpeg -i "{file_path}" -filter:v fps=fps={fps} -c:v {codec} -crf {quality} -c:a aac "{save_path}" -loglevel error -stats -hide_banner -y'
779
796
  subprocess.call(command, shell=True)
780
797
  video_timer.stop_timer()
781
- print(f"Video {file_name} complete (saved at {save_path})... (elapsed time: {video_timer.elapsed_time_str}s)")
798
+ if verbose: print(f"Video {file_name} complete (saved at {save_path})... (elapsed time: {video_timer.elapsed_time_str}s)")
782
799
  timer.stop_timer()
783
- stdout_success(msg=f"SIMBA COMPLETE: FPS of {len(video_paths)} video(s) changed to {fps}", elapsed_time=timer.elapsed_time_str, source=change_fps_of_multiple_videos.__name__,)
800
+ if verbose: stdout_success(msg=f"SIMBA COMPLETE: FPS of {len(video_paths)} video(s) changed to {fps}", elapsed_time=timer.elapsed_time_str, source=change_fps_of_multiple_videos.__name__,)
784
801
 
785
802
 
786
803
  def convert_video_powerpoint_compatible_format(file_path: Union[str, os.PathLike], gpu: Optional[bool] = False) -> None:
@@ -87,8 +87,8 @@ def video_to_frames(video_path: Union[str, os.PathLike],
87
87
  :return: None. Frames are saved to disk in the specified directory.
88
88
 
89
89
  :example:
90
- >>> video_to_frames(video_path=r"C:\troubleshooting\SDS_pre_post\project_folder\videos\SDI100 x ALR2 post_d7.mp4",
91
- ... save_dir=r'C:\troubleshooting\SDS_pre_post\project_folder\videos\test',
90
+ >>> video_to_frames(video_path=r"C:/troubleshooting/SDS_pre_post/project_folder/videos/SDI100 x ALR2 post_d7.mp4",
91
+ ... save_dir=r'C:/troubleshooting/SDS_pre_post/project_folder/videos/test',
92
92
  ... black_and_white=False,
93
93
  ... verbose=True,
94
94
  ... img_format='webp',