simba-uw-tf-dev 4.7.1__py3-none-any.whl → 4.7.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 CHANGED
@@ -1,1171 +1,1178 @@
1
- __author__ = "Simon Nilsson; sronilsson@gmail.com"
2
-
3
- from simba.utils.printing import SimbaTimer, stdout_success, stdout_warning
4
-
5
- load_timer = SimbaTimer(start=True)
6
- import os.path
7
- import warnings
8
-
9
- warnings.filterwarnings("ignore", category=FutureWarning)
10
- warnings.filterwarnings("ignore", category=DeprecationWarning)
11
- import atexit
12
- import platform
13
- import subprocess
14
- import sys
15
- import threading
16
- import tkinter.ttk as ttk
17
- import urllib.request
18
- import webbrowser
19
- from tkinter import *
20
- from tkinter.filedialog import askdirectory
21
- from tkinter.messagebox import askyesno
22
- from typing import Union
23
-
24
- import PIL.Image
25
- from PIL import ImageTk
26
-
27
- from simba.bounding_box_tools.boundary_menus import BoundaryMenus
28
- from simba.labelling.labelling_advanced_interface import \
29
- select_labelling_video_advanced
30
- from simba.labelling.targeted_annotations_clips import \
31
- select_labelling_video_targeted_clips
32
- from simba.mixins.config_reader import ConfigReader
33
- from simba.mixins.pop_up_mixin import PopUpMixin
34
- from simba.model.grid_search_rf import GridSearchRandomForestClassifier
35
- from simba.model.inference_validation import InferenceValidation
36
- from simba.model.train_rf import TrainRandomForestClassifier
37
- from simba.outlier_tools.outlier_corrector_location import \
38
- OutlierCorrecterLocation
39
- from simba.outlier_tools.outlier_corrector_movement import \
40
- OutlierCorrecterMovement
41
- from simba.outlier_tools.skip_outlier_correction import \
42
- OutlierCorrectionSkipper
43
- from simba.plotting.interactive_probability_grapher import \
44
- InteractiveProbabilityGrapher
45
- from simba.third_party_label_appenders.BENTO_appender import BentoAppender
46
- from simba.third_party_label_appenders.BORIS_appender import BorisAppender
47
- from simba.third_party_label_appenders.deepethogram_importer import \
48
- DeepEthogramImporter
49
- from simba.third_party_label_appenders.ethovision_import import \
50
- ImportEthovision
51
- from simba.third_party_label_appenders.observer_importer import \
52
- NoldusObserverImporter
53
- from simba.third_party_label_appenders.solomon_importer import SolomonImporter
54
- from simba.ui.create_project_ui import ProjectCreatorPopUp
55
- from simba.ui.import_pose_frame import ImportPoseFrame
56
- from simba.ui.import_videos_frame import ImportVideosFrame
57
- from simba.ui.machine_model_settings_ui import MachineModelSettingsPopUp
58
- from simba.ui.pop_ups.about_simba_pop_up import AboutSimBAPopUp
59
- from simba.ui.pop_ups.animal_directing_other_animals_pop_up import \
60
- AnimalDirectingAnimalPopUp
61
- from simba.ui.pop_ups.append_roi_features_animals_pop_up import \
62
- AppendROIFeaturesByAnimalPopUp
63
- from simba.ui.pop_ups.append_roi_features_bodypart_pop_up import \
64
- AppendROIFeaturesByBodyPartPopUp
65
- from simba.ui.pop_ups.archive_files_pop_up import ArchiveProcessedFilesPopUp
66
- from simba.ui.pop_ups.batch_preprocess_pop_up import BatchPreProcessPopUp
67
- from simba.ui.pop_ups.blob_visualizer_pop_up import BlobVisualizerPopUp
68
- from simba.ui.pop_ups.boolean_conditional_slicer_pup_up import \
69
- BooleanConditionalSlicerPopUp
70
- from simba.ui.pop_ups.change_speed_popup import ChangeSpeedPopup
71
- from simba.ui.pop_ups.check_videos_seekable_pop_up import \
72
- CheckVideoSeekablePopUp
73
- from simba.ui.pop_ups.clf_add_remove_print_pop_up import (
74
- AddClfPopUp, PrintModelInfoPopUp, RemoveAClassifierPopUp)
75
- from simba.ui.pop_ups.clf_annotation_counts_pop_up import \
76
- ClfAnnotationCountPopUp
77
- from simba.ui.pop_ups.clf_by_roi_pop_up import ClfByROIPopUp
78
- from simba.ui.pop_ups.clf_by_timebins_pop_up import TimeBinsClfPopUp
79
- from simba.ui.pop_ups.clf_descriptive_statistics_pop_up import \
80
- ClfDescriptiveStatsPopUp
81
- from simba.ui.pop_ups.clf_plot_pop_up import SklearnVisualizationPopUp
82
- from simba.ui.pop_ups.clf_probability_plot_pop_up import \
83
- VisualizeClassificationProbabilityPopUp
84
- from simba.ui.pop_ups.clf_validation_plot_pop_up import \
85
- ClassifierValidationPopUp
86
- from simba.ui.pop_ups.coco_keypoints_to_yolo_popup import \
87
- COCOKeypoints2YOLOkeypointsPopUp
88
- from simba.ui.pop_ups.csv_2_parquet_pop_up import (Csv2ParquetPopUp,
89
- Parquet2CsvPopUp)
90
- from simba.ui.pop_ups.cue_light_main_popup import CueLightMainPopUp
91
- from simba.ui.pop_ups.data_plot_pop_up import DataPlotterPopUp
92
- from simba.ui.pop_ups.delete_all_rois_pop_up import delete_all_rois_pop_up
93
- from simba.ui.pop_ups.directing_animal_to_bodypart_plot_pop_up import \
94
- DirectingAnimalToBodyPartVisualizerPopUp
95
- from simba.ui.pop_ups.directing_other_animals_plot_pop_up import \
96
- DirectingOtherAnimalsVisualizerPopUp
97
- from simba.ui.pop_ups.direction_animal_to_bodypart_settings_pop_up import \
98
- DirectionAnimalToBodyPartSettingsPopUp
99
- from simba.ui.pop_ups.distance_plot_pop_up import DistancePlotterPopUp
100
- from simba.ui.pop_ups.dlc_h5_inference_to_yolo_popup import \
101
- DLCH5Inference2YoloPopUp
102
- from simba.ui.pop_ups.dlc_to_labelme_popup import DLC2LabelmePopUp
103
- from simba.ui.pop_ups.dlc_to_yolo_keypoints_popup import DLCYoloKeypointsPopUp
104
- from simba.ui.pop_ups.egocentric_alignment_pop_up import EgocentricAlignPopUp
105
- from simba.ui.pop_ups.extract_annotation_frames_pop_up import \
106
- ExtractAnnotationFramesPopUp
107
- from simba.ui.pop_ups.fsttc_pop_up import FSTTCPopUp
108
- from simba.ui.pop_ups.gantt_pop_up import GanttPlotPopUp
109
- from simba.ui.pop_ups.heatmap_clf_pop_up import HeatmapClfPopUp
110
- from simba.ui.pop_ups.heatmap_location_pop_up import HeatmapLocationPopup
111
- from simba.ui.pop_ups.initialize_blob_tracking_pop_up import \
112
- InitializeBlobTrackerPopUp
113
- from simba.ui.pop_ups.interpolate_pop_up import InterpolatePopUp
114
- from simba.ui.pop_ups.kleinberg_pop_up import KleinbergPopUp
115
- from simba.ui.pop_ups.labelme_bbox_to_yolo_bbox_popup import \
116
- LabelmeBbox2YoloBboxPopUp
117
- from simba.ui.pop_ups.labelme_to_df_popup import Labelme2DataFramePopUp
118
- from simba.ui.pop_ups.labelme_to_imgs_popup import Labelme2ImgsPopUp
119
- from simba.ui.pop_ups.make_path_plot_pop_up import MakePathPlotPopUp
120
- from simba.ui.pop_ups.merge_coco_keypoint_files_pop_up import \
121
- MergeCOCOKeypointFilesPopUp
122
- from simba.ui.pop_ups.movement_analysis_pop_up import \
123
- MovementAnalysisPopUp # ## LAZY
124
- from simba.ui.pop_ups.movement_analysis_time_bins_pop_up import \
125
- MovementAnalysisTimeBinsPopUp
126
- from simba.ui.pop_ups.multiple_videos_to_frames_popup import \
127
- MultipleVideos2FramesPopUp
128
- from simba.ui.pop_ups.mutual_exclusivity_pop_up import MutualExclusivityPupUp
129
- from simba.ui.pop_ups.outlier_settings_pop_up import OutlierSettingsPopUp
130
- from simba.ui.pop_ups.path_plot_pop_up import PathPlotPopUp
131
- from simba.ui.pop_ups.pose_bp_drop_pop_up import DropTrackingDataPopUp
132
- from simba.ui.pop_ups.pose_reorganizer_pop_up import PoseReorganizerPopUp
133
- from simba.ui.pop_ups.print_video_meta_popup import PrintVideoMetaDataPopUp
134
- from simba.ui.pop_ups.pup_retrieval_pop_up import PupRetrievalPopUp
135
- from simba.ui.pop_ups.quick_path_plot_pop_up import QuickLineplotPopup
136
- from simba.ui.pop_ups.remove_roi_features_pop_up import RemoveROIFeaturesPopUp
137
- from simba.ui.pop_ups.roi_aggregate_stats_popup import \
138
- ROIAggregateDataAnalyzerPopUp
139
- from simba.ui.pop_ups.roi_analysis_time_bins_pop_up import \
140
- ROIAnalysisTimeBinsPopUp
141
- from simba.ui.pop_ups.roi_features_plot_pop_up import VisualizeROIFeaturesPopUp
142
- from simba.ui.pop_ups.roi_tracking_plot_pop_up import VisualizeROITrackingPopUp
143
- from simba.ui.pop_ups.roi_video_table_pop_up import ROIVideoTable
144
- from simba.ui.pop_ups.run_machine_models_popup import RunMachineModelsPopUp
145
- from simba.ui.pop_ups.select_video_for_labelling_popup import \
146
- SelectLabellingVideoPupUp
147
- from simba.ui.pop_ups.select_video_for_pseudo_labelling_popup import \
148
- SelectPseudoLabellingVideoPupUp
149
- from simba.ui.pop_ups.severity_analysis_pop_up import AnalyzeSeverityPopUp
150
- from simba.ui.pop_ups.simba_rois_to_yolo_pop_up import SimBAROIs2YOLOPopUp
151
- from simba.ui.pop_ups.simba_to_yolo_keypoints_popup import \
152
- SimBA2YoloKeypointsPopUp
153
- from simba.ui.pop_ups.single_video_to_frames_popup import \
154
- SingleVideo2FramesPopUp
155
- from simba.ui.pop_ups.sleap_annotations_to_yolo_popup import \
156
- SLEAPAnnotations2YoloPopUp
157
- from simba.ui.pop_ups.sleap_csv_predictions_to_yolo_popup import \
158
- SLEAPcsvInference2Yolo
159
- from simba.ui.pop_ups.sleap_h5_inference_to_yolo_popup import \
160
- SLEAPH5Inference2YoloPopUp
161
- from simba.ui.pop_ups.smoothing_popup import SmoothingPopUp
162
- from simba.ui.pop_ups.splash_popup import SplashMovie
163
- from simba.ui.pop_ups.spontaneous_alternation_pop_up import \
164
- SpontaneousAlternationPopUp # ## LAZY
165
- from simba.ui.pop_ups.subset_feature_extractor_pop_up import \
166
- FeatureSubsetExtractorPopUp
167
- from simba.ui.pop_ups.third_party_annotator_appender_pop_up import \
168
- ThirdPartyAnnotatorAppenderPopUp
169
- from simba.ui.pop_ups.validation_plot_pop_up import ValidationVideoPopUp
170
- from simba.ui.pop_ups.video_processing_pop_up import (
171
- BackgroundRemoverDirectoryPopUp, BackgroundRemoverSingleVideoPopUp,
172
- BoxBlurPopUp, BrightnessContrastPopUp, CalculatePixelsPerMMInVideoPopUp,
173
- ChangeFpsMultipleVideosPopUp, ChangeFpsSingleVideoPopUp, CLAHEPopUp,
174
- ClipSingleVideoByFrameNumbers, ClipVideoPopUp, ConcatenatingVideosPopUp,
175
- ConcatenatorPopUp, Convert2AVIPopUp, Convert2BlackWhitePopUp,
176
- Convert2bmpPopUp, Convert2jpegPopUp, Convert2MOVPopUp, Convert2MP4PopUp,
177
- Convert2PNGPopUp, Convert2TIFFPopUp, Convert2WEBMPopUp, Convert2WEBPPopUp,
178
- ConvertROIDefinitionsPopUp, CreateAverageFramePopUp, CreateGIFPopUP,
179
- CropVideoCirclesPopUp, CropVideoPolygonsPopUp, CropVideoPopUp,
180
- CrossfadeVideosPopUp, DownsampleMultipleVideosPopUp,
181
- DownsampleSingleVideoPopUp, ExtractSEQFramesPopUp,
182
- ExtractSpecificFramesPopUp, FlipVideosPopUp, GreyscaleSingleVideoPopUp,
183
- ImportFrameDirectoryPopUp, InitiateClipMultipleVideosByFrameNumbersPopUp,
184
- InitiateClipMultipleVideosByTimestampsPopUp, InteractiveClahePopUp,
185
- ManualTemporalJoinPopUp, MergeFrames2VideoPopUp, MultiCropPopUp,
186
- MultiShortenPopUp, ReverseVideoPopUp, RotateVideoSetDegreesPopUp,
187
- SuperImposeFrameCountPopUp, SuperimposeProgressBarPopUp,
188
- SuperimposeTextPopUp, SuperimposeTimerPopUp, SuperimposeVideoNamesPopUp,
189
- SuperimposeVideoPopUp, SuperimposeWatermarkPopUp, UpsampleVideosPopUp,
190
- VideoRotatorPopUp, VideoTemporalJoinPopUp)
191
- from simba.ui.pop_ups.visualize_pose_in_dir_pop_up import \
192
- VisualizePoseInFolderPopUp
193
- from simba.ui.pop_ups.yolo_inference_popup import YOLOPoseInferencePopUP
194
- from simba.ui.pop_ups.yolo_plot_results import YoloPoseVisualizerPopUp
195
- from simba.ui.pop_ups.yolo_pose_train_popup import YOLOPoseTrainPopUP
196
- from simba.ui.tkinter_functions import (CreateLabelFrameWithIcon, Entry_Box,
197
- FileSelect, SimbaButton, SimbaCheckbox,
198
- SimBADropDown, SimBALabel,
199
- hxtScrollbar)
200
- from simba.ui.video_info_ui import VideoInfoTable
201
- from simba.utils.checks import (check_ffmpeg_available,
202
- check_file_exist_and_readable, check_int)
203
- from simba.utils.custom_feature_extractor import CustomFeatureExtractor
204
- from simba.utils.enums import (ENV_VARS, OS, ConfigKey, Defaults, Dtypes,
205
- Formats, Keys, Links, PackageNames, Paths,
206
- TagNames)
207
- from simba.utils.errors import InvalidInputError
208
- from simba.utils.lookups import (check_for_updates,
209
- get_bp_config_code_class_pairs,
210
- get_current_time, get_emojis, get_icons_paths,
211
- load_simba_fonts)
212
- from simba.utils.read_write import (fetch_pip_data, find_core_cnt,
213
- get_pkg_version, get_recent_projects_paths,
214
- read_config_entry, read_config_file,
215
- read_sys_env, remove_files,
216
- write_to_recent_project_paths)
217
- from simba.utils.warnings import (FFMpegNotFoundWarning, PythonVersionWarning,
218
- VersionWarning)
219
- from simba.video_processors.video_processing import \
220
- extract_frames_from_all_videos_in_directory
221
-
222
- sys.setrecursionlimit(10**6)
223
- currentPlatform = platform.system()
224
- ENV = read_sys_env()
225
- load_timer.stop_timer()
226
- print(f'SimBA environment variables: {ENV}. Load time: {load_timer.elapsed_time_str}s')
227
-
228
- class LoadProjectPopUp(object):
229
- def __init__(self):
230
- self.main_frm = Toplevel()
231
- self.main_frm.minsize(300, 200)
232
- self.main_frm.wm_title("Load SimBA project (project_config.ini file)")
233
- self.btn_icons = get_icons_paths()
234
- for k in self.btn_icons.keys(): self.btn_icons[k]["img"] = ImageTk.PhotoImage(image=PIL.Image.open(os.path.join(os.path.dirname(__file__), self.btn_icons[k]["icon_path"])))
235
- self.main_frm.iconphoto(False, self.btn_icons['browse']["img"])
236
- self.load_project_frm = CreateLabelFrameWithIcon(parent=self.main_frm, header="LOAD SIMBA PROJECT_CONFIG.INI", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.LOAD_PROJECT.value)
237
- self.selected_file = FileSelect(self.load_project_frm, "SIMBA CONFIG FILE: ", title="Select project_config.ini file", file_types=[("SimBA Project .ini", "*.ini")], lblwidth=30, lbl_icon='file_type')
238
- load_project_btn = SimbaButton(parent=self.load_project_frm, txt="LOAD PROJECT PATH", txt_clr='blue', img='rocket', font=Formats.FONT_REGULAR.value, cmd=self.launch_project, cmd_kwargs={'project_path': lambda: self.selected_file.file_path})
239
- #load_project_btn = SimbaButton(parent=self.load_project_frm, txt="LOAD PROJECT PATH", txt_clr='blue', img='rocket', font=Formats.FONT_REGULAR.value, cmd=self.launch_project, cmd_kwargs={'project_path': self.selected_file.file_path})
240
- self.load_project_frm.grid(row=0, sticky=NW, pady=(0, 10))
241
- self.selected_file.grid(row=0, sticky=NW)
242
- load_project_btn.grid(row=1, pady=(3, 0), sticky=NW)
243
- recent_project_paths = get_recent_projects_paths()
244
- if len(recent_project_paths) > 0:
245
- max_len = max(len(s) for s in recent_project_paths)
246
- self.load_recent_frm = CreateLabelFrameWithIcon(parent=self.main_frm, header="LOAD RECENT PROJECT", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.LOAD_PROJECT.value)
247
- self.recent_project_dropdown = SimBADropDown(parent=self.load_recent_frm, dropdown_options=recent_project_paths, label='RECENT CONFIG FILE PATH:', label_width=30, value=recent_project_paths[0], dropdown_width=max_len)
248
- self.load_recent_project_btn = SimbaButton(parent=self.load_recent_frm, txt="LOAD RECENT PROJECT", txt_clr='darkgreen', img='rocket', font=Formats.FONT_REGULAR.value, cmd=self.launch_project, cmd_kwargs={'project_path': lambda: self.recent_project_dropdown.get_value()})
249
- self.load_recent_frm.grid(row=1, sticky=NW)
250
- self.recent_project_dropdown.grid(row=0, sticky=NW)
251
- self.load_recent_project_btn.grid(row=1, pady=(5, 0), sticky=NW)
252
-
253
- def launch_project(self, project_path: str):
254
- check_file_exist_and_readable(file_path=project_path)
255
- _ = SimbaProjectPopUp(config_path=project_path)
256
- self.load_project_frm.destroy()
257
- self.main_frm.destroy()
258
-
259
-
260
- def wait_for_internet_connection(url):
261
- while True:
262
- try:
263
- response = urllib.request.urlopen(url, timeout=1)
264
- return
265
- except:
266
- pass
267
-
268
-
269
- class SimbaProjectPopUp(ConfigReader, PopUpMixin):
270
- """
271
- Main entry to the SimBA loaded project pop-up.
272
- """
273
-
274
- def __init__(self, config_path: Union[str, os.PathLike]):
275
-
276
- ConfigReader.__init__(self, config_path=config_path, read_video_info=False)
277
- stdout_success(f"Loaded project {config_path}", source=self.__class__.__name__)
278
- simongui = Toplevel()
279
- simongui.attributes("-topmost", True)
280
- simongui.after(150, lambda: simongui.attributes("-topmost", False))
281
- simongui.minsize(1300, 800)
282
- try:
283
- config = read_config_file(config_path=config_path)
284
- project_name = read_config_entry(config=config, section=ConfigKey.GENERAL_SETTINGS.value, option=ConfigKey.PROJECT_NAME.value, default_value="LOAD PROJECT", data_type=Dtypes.STR.value)
285
- project_name = f'{project_name} ({config_path})'
286
- except:
287
- project_name = "LOAD PROJECT"
288
- simongui.wm_title(project_name)
289
- simongui.columnconfigure(0, weight=1)
290
- simongui.rowconfigure(0, weight=1)
291
- self.core_cnt = find_core_cnt()[0]
292
- self.btn_icons = get_icons_paths()
293
-
294
- for k in self.btn_icons.keys():
295
- self.btn_icons[k]["img"] = ImageTk.PhotoImage(image=PIL.Image.open(os.path.join(os.path.dirname(__file__), self.btn_icons[k]["icon_path"])))
296
-
297
- simongui.iconphoto(False, self.btn_icons['SimBA_logo_3_small']["img"])
298
- tab_style = ttk.Style()
299
- tab_style.configure('Custom.TNotebook', background='#f0f0f0', borderwidth=0)
300
- tab_style.configure('Custom.TNotebook.Tab', font=Formats.FONT_REGULAR.value, padding=[15, 8], borderwidth=1, relief='flat', background='#f0f0f0')
301
- tab_style.map('Custom.TNotebook.Tab',
302
- background=[('selected', '#ffffff'), ('!selected', '#f0f0f0')],
303
- foreground=[('selected', 'navy'), ('!selected', '#333333')],
304
- font=[('selected', Formats.FONT_REGULAR_BOLD.value), ('!selected', Formats.FONT_REGULAR.value)],
305
- bordercolor=[('selected', '#0066cc'), ('!selected', '#e0e0e0')],
306
- lightcolor=[('selected', '#ffffff'), ('!selected', '#f5f5f5')],
307
- darkcolor=[('selected', '#e0e0e0'), ('!selected', '#e0e0e0')])
308
-
309
- scrollable_container = hxtScrollbar(simongui)
310
- tab_parent = ttk.Notebook(scrollable_container, style='Custom.TNotebook')
311
- tab2 = ttk.Frame(tab_parent)
312
- tab3 = ttk.Frame(tab_parent)
313
- tab4 = ttk.Frame(tab_parent)
314
- tab5 = ttk.Frame(tab_parent)
315
- tab6 = ttk.Frame(tab_parent)
316
- tab7 = ttk.Frame(tab_parent)
317
- tab8 = ttk.Frame(tab_parent)
318
- tab9 = ttk.Frame(tab_parent)
319
- tab10 = ttk.Frame(tab_parent)
320
- tab11 = ttk.Frame(tab_parent)
321
-
322
- tab_parent.add(tab2, text="Further imports", compound="left", image=self.btn_icons["pose"]["img"])
323
- tab_parent.add(tab3, text="Video parameters", compound="left", image=self.btn_icons["calipher"]["img"])
324
- tab_parent.add(tab4, text="Outlier correction", compound="left", image=self.btn_icons["outlier"]["img"])
325
- tab_parent.add(tab6, text="ROI", compound="left", image=self.btn_icons["roi"]["img"])
326
- tab_parent.add(tab5, text="Extract features", compound="left", image=self.btn_icons["features"]["img"])
327
- tab_parent.add(tab7, text="Label behavior", compound="left", image=self.btn_icons["label"]["img"])
328
- tab_parent.add(tab8, text="Train machine model", compound="left", image=self.btn_icons["clf"]["img"])
329
- tab_parent.add(tab9, text="Run machine model", compound="left", image=self.btn_icons["clf_2"]["img"])
330
- tab_parent.add(tab10, text="Visualizations", compound="left", image=self.btn_icons["visualize"]["img"])
331
- tab_parent.add(tab11, text="Add-ons", compound="left", image=self.btn_icons["add_on"]["img"])
332
-
333
- tab_parent.grid(row=0, sticky='ew')
334
- tab_parent.enable_traversal()
335
-
336
- import_frm = LabelFrame(tab2)
337
- import_frm.grid(row=0, column=0, sticky=NW)
338
-
339
- further_methods_frm = CreateLabelFrameWithIcon(parent=import_frm, header="FURTHER METHODS", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.ADDITIONAL_IMPORTS.value, bg=Formats.LABELFRAME_GREY.value, padx=5, pady=5)
340
- extract_frm_btn = SimbaButton(parent=further_methods_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="EXTRACT FRAMES FOR ALL VIDEOS IN SIMBA PROJECT", txt_clr='blue', compound='right', img='image', font=Formats.FONT_REGULAR.value, cmd=extract_frames_from_all_videos_in_directory, cmd_kwargs={'config_path': lambda:self.config_path, 'directory': lambda:self.video_dir})
341
- import_frm_dir_btn = SimbaButton(parent=further_methods_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="IMPORT FRAMES DIRECTORY TO SIMBA PROJECT", txt_clr='blue', compound='right', img='import', font=Formats.FONT_REGULAR.value, cmd=ImportFrameDirectoryPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
342
- add_clf_btn = SimbaButton(parent=further_methods_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="ADD CLASSIFIER TO SIMBA PROJECT", txt_clr='blue', compound='right', img='plus', font=Formats.FONT_REGULAR.value, cmd=AddClfPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
343
- remove_clf_btn = SimbaButton(parent=further_methods_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="REMOVE CLASSIFIER FROM SIMBA PROJECT", txt_clr='blue', compound='right', img='trash', font=Formats.FONT_REGULAR.value, cmd=RemoveAClassifierPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
344
- archive_files_btn = SimbaButton(parent=further_methods_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="ARCHIVE PROCESSED FILES IN SIMBA PROJECT", txt_clr='blue', compound='right', img='archive', font=Formats.FONT_REGULAR.value, cmd=ArchiveProcessedFilesPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
345
- reverse_btn = SimbaButton(parent=further_methods_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="REVERSE TRACKING IDENTITIES IN SIMBA PROJECT", txt_clr='blue', compound='right', img='reverse_blue', font=Formats.FONT_REGULAR.value, cmd=None)
346
- interpolate_btn = SimbaButton(parent=further_methods_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="INTERPOLATE POSE IN SIMBA PROJECT", txt_clr='blue', compound='right', img='line_chart_blue', font=Formats.FONT_REGULAR.value, cmd=InterpolatePopUp, cmd_kwargs={'config_path': lambda:self.config_path})
347
- smooth_btn = SimbaButton(parent=further_methods_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="SMOOTH POSE IN SIMBA PROJECT", txt_clr='blue', compound='right', img='wand_blue', font=Formats.FONT_REGULAR.value, cmd=SmoothingPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
348
- egocentric_align_btn = SimbaButton(parent=further_methods_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="EGOCENTRICALLY ALIGN POSE AND VIDEO", txt_clr='blue', compound='right', img='mouse_small', font=Formats.FONT_REGULAR.value, cmd=EgocentricAlignPopUp, cmd_kwargs={'config_path': lambda: self.config_path})
349
-
350
- label_setscale = CreateLabelFrameWithIcon(parent=tab3, header="VIDEO PARAMETERS (FPS, RESOLUTION, PPX/MM ....)", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.VIDEO_PARAMETERS.value, padx=10, pady=10, relief='solid')
351
- self.distance_in_mm_eb = Entry_Box(label_setscale, "KNOWN DISTANCE (MILLIMETERS): ", labelwidth=35, validation="numeric", entry_box_width=35)
352
- button_setdistanceinmm = SimbaButton(parent=label_setscale, txt="AUTO-POPULATE", txt_clr='blue', font=Formats.FONT_REGULAR.value, cmd=self.set_distance_mm)
353
-
354
- button_setscale = SimbaButton(parent=label_setscale, txt="CONFIGURE VIDEO PARAMETERS", txt_clr='blue', font=Formats.FONT_REGULAR.value, cmd=self.create_video_info_table, img='calipher')
355
- self.new_ROI_frm = CreateLabelFrameWithIcon(parent=tab6, header="SIMBA ROI INTERFACE", icon_name='shapes_small', icon_link=Links.ROI.value, bg='#DCDCDC', padx=5, pady=5)
356
- self.start_new_ROI = SimbaButton(parent=self.new_ROI_frm, width=Formats.BUTTON_WIDTH_L.value, txt="DEFINE ROIs", txt_clr='green', font=Formats.FONT_REGULAR.value, img='roi', cmd=ROIVideoTable, cmd_kwargs={'config_path': lambda:self.config_path})
357
-
358
- self.delete_all_ROIs = SimbaButton(parent=self.new_ROI_frm, width=Formats.BUTTON_WIDTH_L.value, txt="DELETE ALL ROI DEFINITIONS", txt_clr='red', font=Formats.FONT_REGULAR.value, img='trash', cmd=delete_all_rois_pop_up, cmd_kwargs={'config_path': lambda:self.config_path})
359
- self.new_ROI_frm.grid(row=0, sticky=NW, padx=10, pady=10)
360
- self.start_new_ROI.grid(row=0, sticky=NW)
361
- self.delete_all_ROIs.grid(row=1, column=0, sticky=NW)
362
-
363
- self.roi_draw = CreateLabelFrameWithIcon(parent=tab6, header="ANALYZE ROI DATA", icon_name='magnifying', icon_link=Links.ROI.value, bg='#DCDCDC', padx=5, pady=5)
364
- analyze_roi_btn = SimbaButton(parent=self.roi_draw, width=Formats.BUTTON_WIDTH_L.value, txt="ANALYZE ROI DATA: AGGREGATES", txt_clr='green', img='shapes_small', font=Formats.FONT_REGULAR.value, cmd=ROIAggregateDataAnalyzerPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
365
-
366
- analyze_roi_time_bins_btn = SimbaButton(parent=self.roi_draw, width=Formats.BUTTON_WIDTH_L.value, txt="ANALYZE ROI DATA: TIME-BINS", txt_clr='blue', img='clock', font=Formats.FONT_REGULAR.value, cmd=ROIAnalysisTimeBinsPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
367
- self.roi_draw.grid(row=0, column=1, sticky=N, padx=10, pady=10)
368
- analyze_roi_btn.grid(row=0, sticky="NW")
369
- analyze_roi_time_bins_btn.grid(row=1, sticky="NW")
370
-
371
- self.roi_draw1 = CreateLabelFrameWithIcon(parent=tab6, header="VISUALIZE ROI DATA", icon_name='eye', icon_link=Links.ROI.value, bg='#DCDCDC', padx=5, pady=5)
372
- visualizeROI = SimbaButton(parent=self.roi_draw1, width=Formats.BUTTON_WIDTH_L.value, txt="VISUALIZE ROI TRACKING", txt_clr='green', img='visualize_green', font=Formats.FONT_REGULAR.value, cmd=VisualizeROITrackingPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
373
- visualizeROIfeature = SimbaButton(parent=self.roi_draw1, width=Formats.BUTTON_WIDTH_L.value, txt="VISUALIZE ROI FEATURES", txt_clr='blue', img='visualize_blue', font=Formats.FONT_REGULAR.value, cmd=VisualizeROIFeaturesPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
374
-
375
- ##organize
376
- self.roi_draw1.grid(row=0, column=2, sticky=N, padx=10, pady=10)
377
- visualizeROI.grid(row=0, sticky="NW")
378
- visualizeROIfeature.grid(row=1, sticky="NW")
379
-
380
- processmovementdupLabel = CreateLabelFrameWithIcon(parent=tab6, header="OTHER ANALYSES / VISUALIZATIONS", icon_name='list', icon_link=Links.ROI.value, bg='#DCDCDC', padx=5, pady=5)
381
- analyze_distances_velocity_btn = SimbaButton(parent=processmovementdupLabel, width=Formats.BUTTON_WIDTH_XL.value, txt="ANALYZE DISTANCES / VELOCITY: AGGREGATES", img='metrics_green', txt_clr='green', font=Formats.FONT_REGULAR.value, cmd=MovementAnalysisPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
382
- analyze_distances_velocity_timebins_btn = SimbaButton(parent=processmovementdupLabel, width=Formats.BUTTON_WIDTH_XL.value, txt="ANALYZE DISTANCES / VELOCITY: TIME-BINS", img='metrics_blue', txt_clr='blue', font=Formats.FONT_REGULAR.value, cmd=MovementAnalysisTimeBinsPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
383
- heatmaps_location_button = SimbaButton(parent=processmovementdupLabel, width=Formats.BUTTON_WIDTH_XL.value, txt="CREATE LOCATION HEATMAPS", txt_clr='red', img='heatmap', font=Formats.FONT_REGULAR.value, cmd=HeatmapLocationPopup, cmd_kwargs={'config_path': lambda:self.config_path})
384
- button_lineplot = SimbaButton(parent=processmovementdupLabel, width=Formats.BUTTON_WIDTH_XL.value, txt="CREATE PATH PLOTS", txt_clr='orange', img='path', font=Formats.FONT_REGULAR.value, cmd=QuickLineplotPopup, cmd_kwargs={'config_path': lambda:self.config_path})
385
-
386
- button_analyzeDirection = SimbaButton(parent=processmovementdupLabel, width=Formats.BUTTON_WIDTH_XL.value, txt="ANALYZE DIRECTIONALITY BETWEEN ANIMALS", img='direction', txt_clr='deeppink', font=Formats.FONT_REGULAR.value, cmd=AnimalDirectingAnimalPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
387
- button_visualizeDirection = SimbaButton(parent=processmovementdupLabel, width=Formats.BUTTON_WIDTH_XL.value, txt="VISUALIZE DIRECTIONALITY BETWEEN ANIMALS", img='direction', txt_clr='brown', font=Formats.FONT_REGULAR.value, cmd=DirectingOtherAnimalsVisualizerPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
388
- button_analyzeDirection_bp = SimbaButton(parent=processmovementdupLabel, width=Formats.BUTTON_WIDTH_XL.value, txt="ANALYZE DIRECTIONALITY BETWEEN BODY PARTS", img='direction', txt_clr='purple', font=Formats.FONT_REGULAR.value, cmd=DirectionAnimalToBodyPartSettingsPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
389
- button_visualizeDirection_bp = SimbaButton(parent=processmovementdupLabel, width=Formats.BUTTON_WIDTH_XL.value, txt="VISUALIZE DIRECTIONALITY BETWEEN BODY PARTS", img='direction', txt_clr='black', font=Formats.FONT_REGULAR.value, cmd=DirectingAnimalToBodyPartVisualizerPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
390
-
391
- btn_agg_boolean_conditional_statistics = SimbaButton(parent=processmovementdupLabel, width=Formats.BUTTON_WIDTH_XL.value, txt="AGGREGATE BOOLEAN CONDITIONAL STATISTICS", img='details', txt_clr='grey', font=Formats.FONT_REGULAR.value, cmd=BooleanConditionalSlicerPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
392
- spontaneous_alternation_pop_up_btn = SimbaButton(parent=processmovementdupLabel, width=Formats.BUTTON_WIDTH_XL.value, txt="SPONTANEOUS ALTERNATION", img='t', txt_clr='navy', font=Formats.FONT_REGULAR.value, cmd=SpontaneousAlternationPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
393
-
394
- processmovementdupLabel.grid(row=0, column=3, sticky=NW, padx=10, pady=10)
395
- analyze_distances_velocity_btn.grid(row=0, sticky=NW)
396
- heatmaps_location_button.grid(row=1, sticky=NW)
397
- analyze_distances_velocity_timebins_btn.grid(row=2, sticky=NW)
398
- button_lineplot.grid(row=3, sticky=NW)
399
- button_analyzeDirection.grid(row=4, sticky=NW)
400
- button_visualizeDirection.grid(row=5, sticky=NW)
401
- button_analyzeDirection_bp.grid(row=6, sticky=NW)
402
- button_visualizeDirection_bp.grid(row=7, sticky=NW)
403
- btn_agg_boolean_conditional_statistics.grid(row=8, sticky=NW)
404
- spontaneous_alternation_pop_up_btn.grid(row=9, sticky=NW)
405
-
406
- label_outliercorrection = CreateLabelFrameWithIcon(parent=tab4, header="OUTLIER CORRECTION", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.OUTLIERS_DOC.value, bg=Formats.LABELFRAME_GREY.value, padx=5, pady=5)
407
- button_settings_outlier = SimbaButton(parent=label_outliercorrection, width=Formats.BUTTON_WIDTH_L.value, txt="SETTINGS", txt_clr='blue', img='settings', font=Formats.FONT_REGULAR.value, cmd=OutlierSettingsPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
408
-
409
- button_outliercorrection = SimbaButton(parent=label_outliercorrection, width=Formats.BUTTON_WIDTH_L.value, txt="RUN OUTLIER CORRECTION", txt_clr='green', img='rocket', font=Formats.FONT_REGULAR.value, cmd=self.correct_outlier, thread=False)
410
- button_skipOC = SimbaButton(parent=label_outliercorrection, width=Formats.BUTTON_WIDTH_L.value, txt="SKIP OUTLIER CORRECTION (CAUTION)", txt_clr='red', img='skip_2', font=Formats.FONT_REGULAR.value, cmd=self.initiate_skip_outlier_correction, thread=False)
411
-
412
- def activate():
413
- if self.user_defined_var.get(): self.scriptfile.set_state(setstatus=NORMAL)
414
- else: self.scriptfile.set_state(setstatus=DISABLED)
415
-
416
- extract_features_frm = CreateLabelFrameWithIcon(parent=tab5, header="EXTRACT FEATURES", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.EXTRACT_FEATURES.value, relief='solid')
417
- userscript, self.user_defined_var = SimbaCheckbox(parent=extract_features_frm, txt="APPLY USER DEFINED FEATURE EXTRACTION SCRIPT", font=Formats.FONT_REGULAR.value, val=False, state=NORMAL, cmd= activate)
418
- self.scriptfile = FileSelect(extract_features_frm, "SCRIPT PATH (.PY):", file_types=[("Python .py file", "*.py")], lblwidth=25, status=DISABLED, lbl_icon='python')
419
- button_extractfeatures = SimbaButton(parent=extract_features_frm, txt="EXTRACT FEATURES", width=Formats.BUTTON_WIDTH_XL.value, txt_clr='blue', img='rocket', font=Formats.FONT_REGULAR.value, cmd=self.run_feature_extraction, thread=False)
420
-
421
- extract_features_frm.grid(row=0, column=0, sticky=NSEW, padx=10, pady=10)
422
- userscript.grid(row=0, column=0, sticky=NW)
423
- self.scriptfile.grid(row=1, column=0, sticky=NW)
424
- button_extractfeatures.grid(row=2, column=0, sticky=NW)
425
-
426
- roi_feature_frm = CreateLabelFrameWithIcon(parent=tab5, header="APPEND ROI FEATURES", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.APPEND_ROI_FEATURES.value, bg=Formats.LABELFRAME_GREY.value, padx=5, pady=5)
427
-
428
- append_roi_features_by_animal = SimbaButton(parent=roi_feature_frm, width=Formats.BUTTON_WIDTH_XXL.value, txt="APPEND ROI DATA TO FEATURES: BY ANIMAL (CAUTION)", txt_clr='red', img='join_red', font=Formats.FONT_REGULAR.value, cmd=AppendROIFeaturesByAnimalPopUp, cmd_kwargs={'config_path': lambda:self.config_path}, thread=False)
429
- append_roi_features_by_body_part = SimbaButton(parent=roi_feature_frm, width=Formats.BUTTON_WIDTH_XXL.value, txt="APPEND ROI DATA TO FEATURES: BY BODY-PARTS (CAUTION)", img='join_yellow', txt_clr='orange', font=Formats.FONT_REGULAR.value, cmd=AppendROIFeaturesByBodyPartPopUp, cmd_kwargs={'config_path': lambda:self.config_path}, thread=False)
430
- remove_roi_features_from_feature_set = SimbaButton(parent=roi_feature_frm, width=Formats.BUTTON_WIDTH_XXL.value, txt="REMOVE ROI FEATURES FROM FEATURE SET", txt_clr='darkred', img='trash', font=Formats.FONT_REGULAR.value, cmd=RemoveROIFeaturesPopUp, cmd_kwargs={'config_path': lambda:self.config_path, 'dataset': lambda:'features_extracted'}, thread=False)
431
-
432
-
433
- feature_tools_frm = LabelFrame(tab5, text="FEATURE TOOLS", pady=5, font=Formats.FONT_HEADER.value, bg=Formats.LABELFRAME_GREY.value, padx=5)
434
- compute_feature_subset_btn = SimbaButton(parent=feature_tools_frm, width=Formats.BUTTON_WIDTH_XXL.value, txt="CALCULATE FEATURE SUBSETS", txt_clr='blue', img='subset_blue', font=Formats.FONT_REGULAR.value, cmd=FeatureSubsetExtractorPopUp, cmd_kwargs={'config_path': lambda: self.config_path}, thread=False)
435
-
436
- label_behavior_frm = CreateLabelFrameWithIcon(parent=tab7, header="LABEL BEHAVIOR", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.LABEL_BEHAVIOR.value, bg=Formats.LABELFRAME_GREY.value, padx=5, pady=5)
437
- select_video_btn_new = SimbaButton(parent=label_behavior_frm, width=Formats.BUTTON_WIDTH_XXL.value, txt="Select video (create NEW video annotation)", img='label_blue', txt_clr='navy', cmd=SelectLabellingVideoPupUp, cmd_kwargs={'config_path': lambda :self.config_path, 'continuing': lambda: False}, thread=False)
438
- select_video_btn_continue = SimbaButton(parent=label_behavior_frm, width=Formats.BUTTON_WIDTH_XXL.value, txt="Select video (CONTINUE existing video annotation)", img='label_yellow', txt_clr='darkgoldenrod', cmd=SelectLabellingVideoPupUp, cmd_kwargs={'config_path': lambda: self.config_path,'continuing': lambda: True}, thread=False)
439
-
440
- label_thirdpartyann = CreateLabelFrameWithIcon(parent=tab7, header="IMPORT THIRD-PARTY BEHAVIOR ANNOTATIONS", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.THIRD_PARTY_ANNOTATION.value, bg=Formats.LABELFRAME_GREY.value, padx=5, pady=5)
441
- button_importmars = SimbaButton(parent=label_thirdpartyann, width=Formats.BUTTON_WIDTH_XS.value, txt="Import MARS Annotation (select folder with .annot files)", txt_clr="blue", cmd=self.importMARS, thread=False, font=Formats.FONT_REGULAR.value)
442
- button_importboris = SimbaButton(parent=label_thirdpartyann, width=Formats.BUTTON_WIDTH_XS.value, txt="Import BORIS Annotation (select folder with .csv files)", txt_clr="green", cmd=self.importBoris, thread=False, font=Formats.FONT_REGULAR.value)
443
- button_importsolomon = SimbaButton(parent=label_thirdpartyann, width=Formats.BUTTON_WIDTH_XS.value, txt="Import SOLOMON Annotation (select folder with .csv files", txt_clr="purple", cmd=self.importSolomon, thread=False, font=Formats.FONT_REGULAR.value)
444
-
445
- button_importethovision = SimbaButton(parent=label_thirdpartyann, width=Formats.BUTTON_WIDTH_XS.value, txt="Import ETHOVISION Annotation (select folder with .xls/xlsx files)", txt_clr="blue", cmd=self.import_ethovision, thread=False, font=Formats.FONT_REGULAR.value)
446
- button_importdeepethogram = SimbaButton(parent=label_thirdpartyann, width=Formats.BUTTON_WIDTH_XS.value, txt="Import DEEPETHOGRAM Annotation (select folder with .csv files)", txt_clr="green", cmd=self.import_deepethogram, thread=False, font=Formats.FONT_REGULAR.value)
447
- import_observer_btn = SimbaButton(parent=label_thirdpartyann, width=Formats.BUTTON_WIDTH_XS.value, txt="Import NOLDUS OBSERVER Annotation (select folder with .xls/xlsx files)", txt_clr="purple", cmd=self.import_noldus_observer, thread=False, font=Formats.FONT_REGULAR.value)
448
-
449
-
450
- label_pseudo = CreateLabelFrameWithIcon(parent=tab7,header="PSEUDO-LABELLING", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.PSEUDO_LBL.value, bg=Formats.LABELFRAME_GREY.value, padx=5, pady=5)
451
- pseudo_lbelling_btn = SimbaButton(parent=label_pseudo, width=Formats.BUTTON_WIDTH_XXL.value, txt="PSEUDO-LABEL VIDEO", img='label_blue', txt_clr='navy', cmd=SelectPseudoLabellingVideoPupUp, cmd_kwargs={'config_path': lambda :self.config_path}, thread=False)
452
-
453
- label_adv_label = CreateLabelFrameWithIcon(parent=tab7, header="ADVANCED LABEL BEHAVIOR", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.ADVANCED_LBL.value, bg=Formats.LABELFRAME_GREY.value, padx=5, pady=5)
454
-
455
- label_adv_note_1 = SimBALabel(parent=label_adv_label, txt="Note: you will have to specify the presence of *both* behavior and non-behavior on your own.", font=Formats.FONT_REGULAR.value, bg_clr=Formats.LABELFRAME_GREY.value)
456
- label_adv_note_2 = SimBALabel(parent=label_adv_label, txt="Click here more information on how to use the SimBA labelling interface.", txt_clr='blue', cursor='hand2', font=Formats.FONT_REGULAR.value, link=Links.ADVANCED_LBL.value,bg_clr=Formats.LABELFRAME_GREY.value)
457
-
458
- adv_label_btn_new = SimbaButton(parent=label_adv_label, width=Formats.BUTTON_WIDTH_XS.value, txt="Select video (create NEW video annotation)", cmd=select_labelling_video_advanced, cmd_kwargs={'config_path': lambda:self.config_path, 'continuing': lambda:False}, thread=False)
459
- adv_label_btn_continue = SimbaButton(parent=label_adv_label, width=Formats.BUTTON_WIDTH_XS.value, txt="Select video (CONTINUE existing video annotation)", cmd=select_labelling_video_advanced, cmd_kwargs={'config_path': lambda:self.config_path, 'continuing': lambda:True}, thread=False)
460
-
461
- targeted_clip_annotator_frm = CreateLabelFrameWithIcon(parent=tab7,header="TARGETED CLIP ANNOTATOR",icon_name=Keys.DOCUMENTATION.value,icon_link=Links.ADVANCED_LBL.value, bg=Formats.LABELFRAME_GREY.value, padx=5, pady=5)
462
- targeted_clip_annotator_note = SimBALabel(parent=targeted_clip_annotator_frm, txt="A bout annotator that creates annotated clips from videos associated with ML results.", txt_clr='blue', cursor='hand2', font=Formats.FONT_REGULAR.value, link=Links.ADVANCED_LBL.value, bg_clr=Formats.LABELFRAME_GREY.value)
463
- targeted_clip_annotator_btn = SimbaButton(parent=targeted_clip_annotator_frm, txt="Select video", cmd=select_labelling_video_targeted_clips, cmd_kwargs={'config_path': lambda:self.config_path}, thread=False)
464
-
465
- lbl_tools_frm = CreateLabelFrameWithIcon(parent=tab7, header="LABELLING TOOLS", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.ADVANCED_LBL.value, bg=Formats.LABELFRAME_GREY.value, padx=5, pady=5)
466
- visualize_annotation_img_btn = SimbaButton(parent=lbl_tools_frm, width=Formats.BUTTON_WIDTH_XS.value, txt="VISUALIZE ANNOTATIONS", cmd=ExtractAnnotationFramesPopUp, cmd_kwargs={'config_path': lambda:self.config_path}, thread=False)
467
- third_party_annotations_btn = SimbaButton(parent=lbl_tools_frm, width=Formats.BUTTON_WIDTH_XS.value, txt="APPEND THIRD-PARTY ANNOTATIONS", txt_clr='purple', cmd=ThirdPartyAnnotatorAppenderPopUp, cmd_kwargs={'config_path': lambda:self.config_path}, thread=False)
468
- remove_roi_features_from_annotation_set = SimbaButton(parent=lbl_tools_frm, width=Formats.BUTTON_WIDTH_XS.value, txt="REMOVE ROI FEATURES FROM LABEL SET", txt_clr='darkred', cmd=RemoveROIFeaturesPopUp, cmd_kwargs={'config_path': lambda:self.config_path, 'dataset': lambda:'targets_inserted'}, thread=False)
469
- compute_annotation_statistics = SimbaButton(parent=lbl_tools_frm, width=Formats.BUTTON_WIDTH_XS.value, txt="COUNT ANNOTATIONS IN PROJECT", txt_clr='orange', cmd=ClfAnnotationCountPopUp, cmd_kwargs={'config_path': lambda:self.config_path}, thread=False)
470
-
471
-
472
-
473
- label_trainmachinemodel = CreateLabelFrameWithIcon(parent=tab8, header="TRAIN MACHINE MODELS", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.TRAIN_ML_MODEL.value, bg=Formats.LABELFRAME_GREY.value, padx=5, pady=5)
474
-
475
-
476
- button_trainmachinesettings = SimbaButton(parent=label_trainmachinemodel, width=Formats.BUTTON_WIDTH_XXL.value, txt="SETTINGS", img='settings', txt_clr='darkorange', cmd=self.trainmachinemodelsetting, thread=False)
477
- button_trainmachinemodel = SimbaButton(parent=label_trainmachinemodel, width=Formats.BUTTON_WIDTH_XXL.value, txt="TRAIN SINGLE MODEL (GLOBAL ENVIRONMENT)", img='one_blue', txt_clr='blue', cmd=self.train_single_model, cmd_kwargs={'config_path': lambda:self.config_path}, thread=False)
478
-
479
- button_train_multimodel = SimbaButton(parent=label_trainmachinemodel, width=Formats.BUTTON_WIDTH_XXL.value, txt="TRAIN MULTIPLE MODELS (ONE FOR EACH SAVED SETTING)", img='multiple_green', txt_clr='green', cmd=self.train_multiple_models_from_meta, cmd_kwargs={'config_path': lambda:self.config_path}, thread=False)
480
-
481
- label_model_validation = CreateLabelFrameWithIcon( parent=tab9, header="VALIDATE MODEL ON SINGLE VIDEO", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.OUT_OF_SAMPLE_VALIDATION.value, padx=5, pady=5, relief='solid')
482
- self.csvfile = FileSelect(label_model_validation,fileDescription="SELECT DATA FEATURE FILE PATH", color="blue",lblwidth=40,file_types=[("SimBA CSV", "*.csv"), ("SimBA PARQUET", "*.parquet")], initialdir=os.path.join(self.project_path, Paths.FEATURES_EXTRACTED_DIR.value))
483
- self.modelfile = FileSelect(label_model_validation,fileDescription="SELECT MODEL FILE PATH", color="blue", lblwidth=40, initialdir=self.project_path)
484
-
485
- button_runvalidmodel = SimbaButton(parent=label_model_validation, width=Formats.BUTTON_WIDTH_XL.value, txt="RUN MODEL", txt_clr='blue', img='rocket', cmd=self.validate_model_first_step, thread=False)
486
- button_generateplot = SimbaButton(parent=label_model_validation, width=Formats.BUTTON_WIDTH_XL.value, txt="INTERACTIVE PROBABILITY PLOT", img='interactive_blue', txt_clr='blue', cmd=self.launch_interactive_plot, thread=False)
487
-
488
- self.dis_threshold = Entry_Box(label_model_validation, "DISCRIMINATION THRESHOLD (0.0-1.0):", labelwidth=40, entry_box_width=30)
489
- self.min_behaviorbout = Entry_Box(label_model_validation,"MINIMUM BOUT LENGTH (MS):",labelwidth=40, validation="numeric", entry_box_width=30)
490
- button_validate_model = SimbaButton(parent=label_model_validation, width=Formats.BUTTON_WIDTH_XL.value, txt="CREATE VALIDATION VIDEO", txt_clr='blue', img='visualize_blue', cmd=ValidationVideoPopUp, cmd_kwargs={'config_path': lambda: config_path,
491
- 'feature_path': lambda: self.csvfile.file_path,
492
- 'model_path': lambda: self.modelfile.file_path,
493
- 'discrimination_threshold': lambda: self.dis_threshold.entry_get,
494
- 'shortest_bout': lambda: self.min_behaviorbout.entry_get})
495
-
496
- label_runmachinemodel = CreateLabelFrameWithIcon(parent=tab9,header="RUN MACHINE MODEL",icon_name=Keys.DOCUMENTATION.value,icon_link=Links.SCENARIO_2.value, bg=Formats.LABELFRAME_GREY.value, padx=5, pady=5)
497
-
498
- button_runmachinemodel = SimbaButton(parent=label_runmachinemodel, width=Formats.BUTTON_WIDTH_XL.value, txt="RUN MODELS", txt_clr='green', img='clf', cmd=RunMachineModelsPopUp, thread=False, cmd_kwargs={'config_path': lambda:self.config_path})
499
-
500
- kleinberg_button = SimbaButton(parent=label_runmachinemodel, width=Formats.BUTTON_WIDTH_XL.value, txt="KLEINBERG SMOOTHING", txt_clr='green', img='feather_green', cmd=KleinbergPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
501
- fsttc_button = SimbaButton(parent=label_runmachinemodel, width=Formats.BUTTON_WIDTH_XL.value, txt="FSTTC", txt_clr='green', img='tile_green', cmd=FSTTCPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
502
-
503
- mutual_exclusivity = SimbaButton(parent=label_runmachinemodel, width=Formats.BUTTON_WIDTH_XL.value, txt="MUTUAL EXCLUSIVITY CORRECTION", img='seperate_green', txt_clr='green', cmd=MutualExclusivityPupUp, cmd_kwargs={'config_path': lambda:self.config_path})
504
-
505
- label_machineresults = CreateLabelFrameWithIcon( parent=tab9, header="ANALYZE MACHINE RESULTS", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.ANALYZE_ML_RESULTS.value, bg=Formats.LABELFRAME_GREY.value, pady=5, padx=5)
506
-
507
-
508
- button_process_datalog = SimbaButton(parent=label_machineresults, width=Formats.BUTTON_WIDTH_XL.value, txt="ANALYZE MACHINE PREDICTIONS: AGGREGATES", img='metrics_blue', txt_clr='blue', cmd=ClfDescriptiveStatsPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
509
- button_process_movement = SimbaButton(parent=label_machineresults, width=Formats.BUTTON_WIDTH_XL.value, txt="ANALYZE DISTANCES/VELOCITY: AGGREGATES", img='metrics_blue', txt_clr='blue', cmd=MovementAnalysisPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
510
- button_movebins = SimbaButton(parent=label_machineresults, width=Formats.BUTTON_WIDTH_XL.value, txt="ANALYZE DISTANCES/VELOCITY: TIME BINS", txt_clr='blue', img='metrics_blue', cmd=MovementAnalysisTimeBinsPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
511
- button_classifierbins = SimbaButton(parent=label_machineresults, width=Formats.BUTTON_WIDTH_XL.value, txt="ANALYZE MACHINE PREDICTIONS: TIME-BINS", txt_clr='blue', img='metrics_blue', cmd=TimeBinsClfPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
512
- button_classifier_ROI = SimbaButton(parent=label_machineresults, width=Formats.BUTTON_WIDTH_XL.value, txt="ANALYZE MACHINE PREDICTION: BY ROI", txt_clr='blue', img='metrics_blue', cmd=ClfByROIPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
513
- button_severity = SimbaButton(parent=label_machineresults, width=Formats.BUTTON_WIDTH_XL.value, txt="ANALYZE MACHINE PREDICTION: BY SEVERITY", txt_clr='blue', img='metrics_blue', cmd=AnalyzeSeverityPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
514
-
515
- visualization_frm = CreateLabelFrameWithIcon(parent=tab10, header="DATA VISUALIZATIONS", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.VISUALIZATION.value, bg=Formats.LABELFRAME_GREY.value, padx=5, pady=5)
516
- sklearn_visualization_btn = SimbaButton(parent=visualization_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="VISUALIZE CLASSIFICATIONS", img='split', txt_clr='black', cmd=SklearnVisualizationPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
517
- sklearn_visualization_btn.grid(row=0, column=0, sticky=NW)
518
- gantt_visualization_btn = SimbaButton(parent=visualization_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="VISUALIZE GANTT", img='bar_graph_blue', txt_clr='blue', cmd=GanttPlotPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
519
- gantt_visualization_btn.grid(row=1, column=0, sticky=NW)
520
- probability_visualization_btn = SimbaButton(parent=visualization_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="VISUALIZE PROBABILITIES", img='dice_green', txt_clr='green', cmd=VisualizeClassificationProbabilityPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
521
- probability_visualization_btn.grid(row=2, column=0, sticky=NW)
522
- path_visualization_btn = SimbaButton(parent=visualization_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="VISUALIZE PATHS", img='path', txt_clr='navy', cmd=PathPlotPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
523
- path_visualization_btn.grid(row=3, column=0, sticky=NW)
524
- distance_visualization_btn = SimbaButton(parent=visualization_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="VISUALIZE DISTANCES", img='distance_red', txt_clr='red', cmd=DistancePlotterPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
525
- distance_visualization_btn.grid(row=4, column=0, sticky=NW)
526
- heatmap_clf_visualization_btn = SimbaButton(parent=visualization_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="VISUALIZE CLASSIFICATION HEATMAPS", img='heatmap', txt_clr='green', cmd=HeatmapClfPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
527
- heatmap_clf_visualization_btn.grid(row=5, column=0, sticky=NW)
528
- #data_plot_visualization_btn = SimbaButton(parent=visualization_frm, txt="VISUALIZE DATA PLOTS", img='metrics', txt_clr='purple', cmd=Nne, cmd_kwargs={'config_path': lambda:self.config_path})
529
- data_plot_visualization_btn = SimbaButton(parent=visualization_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="VISUALIZE DATA PLOTS", img='metrics', txt_clr='purple', cmd=DataPlotterPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
530
-
531
-
532
- data_plot_visualization_btn.grid(row=6, column=0, sticky=NW)
533
- clf_validation_btn = SimbaButton(parent=visualization_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="CLASSIFIER VALIDATION CLIPS", txt_clr='blue', img='check_blue', cmd=ClassifierValidationPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
534
- clf_validation_btn.grid(row=7, column=0, sticky=NW)
535
- merge_frm = CreateLabelFrameWithIcon(parent=tab10, header="MERGE FRAMES", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.CONCAT_VIDEOS.value)
536
- merge_frm_btn = SimbaButton(parent=merge_frm, txt="MERGE FRAMES", img='merge', txt_clr='black', cmd=ConcatenatorPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
537
- plotlyInterface = CreateLabelFrameWithIcon(parent=tab10, header="PLOTLY / DASH", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.PLOTLY.value)
538
- plotlyInterfaceTitles = ["Sklearn results", "Time bin analyses", "Probabilities", "Severity analysis"]
539
- toIncludeVar = []
540
- for i in range(len(plotlyInterfaceTitles) + 1):
541
- toIncludeVar.append(IntVar())
542
- plotlyCheckbox = [0] * (len(plotlyInterfaceTitles) + 1)
543
- for i in range(len(plotlyInterfaceTitles)):
544
- plotlyCheckbox[i] = Checkbutton(plotlyInterface, text=plotlyInterfaceTitles[i], variable=toIncludeVar[i])
545
- plotlyCheckbox[i].grid(row=i, sticky=W)
546
-
547
- button_save_plotly_file = Button(plotlyInterface, text="Save SimBA / Plotly dataset", command=lambda: self.generateSimBPlotlyFile(toIncludeVar))
548
- self.plotly_file = FileSelect( plotlyInterface, "SimBA Dashboard file (H5)", title="Select SimBA/Plotly dataset (h5)")
549
- self.groups_file = FileSelect(plotlyInterface, "SimBA Groups file (CSV)", title="Select groups file (csv)")
550
- button_open_plotly_interface = Button(plotlyInterface, text="Open SimBA / Plotly dataset", font=Formats.FONT_REGULAR.value, fg="black", command=lambda: [self.open_plotly_interface("http://127.0.0.1:8050")])
551
-
552
-
553
- lbl_addon = CreateLabelFrameWithIcon(parent=tab11, header="SimBA EXPANSIONS", icon_name='plus_green_2')
554
- #button_bel = SimbaButton(parent=lbl_addon, txt="Pup retrieval - Analysis Protocol 1", txt_clr='blue', cmd=None, cmd_kwargs={'config_path': lambda:self.config_path})
555
- button_bel = SimbaButton(parent=lbl_addon, txt="PUP RETRIEVAL - ANALYSIS PROTOCOL 1", txt_clr='blue', cmd=PupRetrievalPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
556
- #cue_light_analyser_btn = SimbaButton(parent=lbl_addon, txt="Cue light analysis", txt_clr='red', cmd=None, cmd_kwargs={'config_path': lambda:self.config_path})
557
- cue_light_analyser_btn = SimbaButton(parent=lbl_addon, txt="CUE LIGHT ANALYSIS", txt_clr='red', img='light_bulb', cmd=CueLightMainPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
558
-
559
-
560
-
561
- anchored_roi_analysis_btn = SimbaButton(parent=lbl_addon, txt="ANIMAL-ANCHORED ROIs", txt_clr='orange', cmd=BoundaryMenus, cmd_kwargs={'config_path': lambda:self.config_path})
562
- ImportVideosFrame(parent_frm=import_frm, config_path=config_path, idx_row=0, idx_column=0)
563
- ImportPoseFrame(parent_frm=import_frm, idx_row=1, idx_column=0, config_path=config_path)
564
- further_methods_frm.grid(row=0, column=1, sticky=NW, pady=10, padx=10)
565
- extract_frm_btn.grid(row=1, column=0, sticky=NW)
566
- import_frm_dir_btn.grid(row=2, column=0, sticky=NW)
567
- add_clf_btn.grid(row=3, column=0, sticky=NW)
568
- remove_clf_btn.grid(row=4, column=0, sticky=NW)
569
- archive_files_btn.grid(row=5, column=0, sticky=NW)
570
- reverse_btn.grid(row=6, column=0, sticky=NW)
571
- interpolate_btn.grid(row=7, column=0, sticky=NW)
572
- smooth_btn.grid(row=8, column=0, sticky=NW)
573
- egocentric_align_btn.grid(row=9, column=0, sticky=NW)
574
-
575
- label_setscale.grid(row=0, sticky=NW, pady=20, padx=20)
576
- self.distance_in_mm_eb.grid(row=0, column=0, sticky=NW)
577
- button_setdistanceinmm.grid(row=0, column=1, sticky=NW)
578
- button_setscale.grid(row=1, column=0, sticky=NW)
579
-
580
- label_outliercorrection.grid(row=0, sticky=W, padx=10, pady=10)
581
- button_settings_outlier.grid(row=0, sticky=W)
582
- button_outliercorrection.grid(row=1, sticky=W)
583
- button_skipOC.grid(row=2, sticky=W, pady=5)
584
-
585
-
586
- roi_feature_frm.grid(row=1, column=0, sticky=NW, padx=10, pady=10)
587
- append_roi_features_by_animal.grid(row=0, column=0, sticky=NW)
588
- append_roi_features_by_body_part.grid(row=1, column=0, sticky=NW)
589
- remove_roi_features_from_feature_set.grid(row=2, column=0, sticky=NW)
590
-
591
- feature_tools_frm.grid(row=2, column=0, sticky=NW, padx=10, pady=10)
592
- compute_feature_subset_btn.grid(row=0, column=0, sticky=NW)
593
-
594
- label_behavior_frm.grid(row=5, sticky=W, padx=10, pady=10)
595
- select_video_btn_new.grid(row=0, sticky=W)
596
- select_video_btn_continue.grid(row=1, sticky=W)
597
-
598
- label_pseudo.grid(row=6, sticky=W, padx=10, pady=10)
599
- pseudo_lbelling_btn.grid(row=0, column=0, sticky=W, pady=10)
600
-
601
- label_adv_label.grid(row=7, column=0, sticky=NW, padx=10, pady=10)
602
- label_adv_note_1.grid(row=0, column=0, sticky=NW)
603
- label_adv_note_2.grid(row=1, column=0, sticky=NW)
604
- adv_label_btn_new.grid(row=3, column=0, sticky=NW)
605
- adv_label_btn_continue.grid(row=4, column=0, sticky=NW)
606
-
607
- targeted_clip_annotator_frm.grid(row=8, column=0, sticky=NW, padx=10, pady=10)
608
- targeted_clip_annotator_note.grid(row=0, column=0, sticky=NW)
609
- targeted_clip_annotator_btn.grid(row=1, column=0, sticky=NW)
610
-
611
- label_thirdpartyann.grid(row=9, sticky=W, padx=10, pady=10)
612
- button_importmars.grid(row=0, column=0, sticky=NW)
613
- button_importboris.grid(row=1, column=0, sticky=NW)
614
- button_importsolomon.grid(row=2, column=0, sticky=NW)
615
- button_importethovision.grid(row=0, column=1, sticky=NW)
616
- button_importdeepethogram.grid(row=1, column=1, sticky=NW)
617
- import_observer_btn.grid(row=2, column=1, sticky=NW)
618
-
619
- lbl_tools_frm.grid(row=10, column=0, sticky=NW, padx=10, pady=10)
620
- visualize_annotation_img_btn.grid(row=0, column=0, sticky=NW)
621
- third_party_annotations_btn.grid(row=0, column=1, sticky=NW)
622
- remove_roi_features_from_annotation_set.grid(row=1, column=0, sticky=NW)
623
- compute_annotation_statistics.grid(row=1, column=1, sticky=NW)
624
-
625
- label_trainmachinemodel.grid(row=6, sticky=W, padx=10, pady=10)
626
- button_trainmachinesettings.grid(row=0, column=0, sticky=NW, padx=5)
627
- button_trainmachinemodel.grid(row=1, column=0, sticky=NW, padx=5)
628
- button_train_multimodel.grid(row=2, column=0, sticky=NW, padx=5)
629
-
630
- label_model_validation.grid(row=7, sticky=W, pady=10, padx=10)
631
- self.csvfile.grid(row=0, sticky=W)
632
- self.modelfile.grid(row=1, sticky=W)
633
- button_runvalidmodel.grid(row=2, sticky=W)
634
- button_generateplot.grid(row=3, sticky=W)
635
- self.dis_threshold.grid(row=4, sticky=W)
636
- self.min_behaviorbout.grid(row=5, sticky=W)
637
- button_validate_model.grid(row=6, sticky=W)
638
-
639
- label_runmachinemodel.grid(row=8, sticky=NW, padx=10, pady=10)
640
- button_runmachinemodel.grid(row=0, sticky=NW)
641
- kleinberg_button.grid(row=1, sticky=NW)
642
- fsttc_button.grid(row=2, sticky=NW)
643
- mutual_exclusivity.grid(row=3, sticky=NW)
644
-
645
- label_machineresults.grid(row=9, sticky=W, padx=10, pady=10)
646
- button_process_datalog.grid(row=2, column=0, sticky=W, padx=3)
647
- button_process_movement.grid(row=2, column=1, sticky=W, padx=3)
648
- button_movebins.grid(row=3, column=1, sticky=W, padx=3)
649
- button_classifierbins.grid(row=3, column=0, sticky=W, padx=3)
650
- button_classifier_ROI.grid(row=4, column=0, sticky=W, padx=3)
651
- button_severity.grid(row=4, column=1, sticky=W, padx=3)
652
-
653
- visualization_frm.grid(row=11, column=0, sticky=W + N, padx=10, pady=10)
654
- merge_frm.grid(row=11, column=2, sticky=W + N, padx=5)
655
- merge_frm_btn.grid(row=0, sticky=NW, padx=5)
656
-
657
- plotlyInterface.grid(row=11, column=3, sticky=W + N, padx=5)
658
- button_save_plotly_file.grid(row=10, sticky=W)
659
- self.plotly_file.grid(row=11, sticky=W)
660
- self.groups_file.grid(row=12, sticky=W)
661
- button_open_plotly_interface.grid(row=13, sticky=W)
662
-
663
- lbl_addon.grid(row=0, sticky=W)
664
- button_bel.grid(row=0, sticky=W)
665
- cue_light_analyser_btn.grid(row=1, sticky=NW)
666
- anchored_roi_analysis_btn.grid(row=2, sticky=NW)
667
-
668
- if ENV[ENV_VARS.UNSUPERVISED_INTERFACE.value]:
669
- from simba.unsupervised.unsupervised_main import UnsupervisedGUI
670
- unsupervised_btn = Button(lbl_addon, text="Unsupervised analysis", fg="purple", font=Formats.FONT_REGULAR.value, command=lambda: UnsupervisedGUI(config_path=self.config_path))
671
- unsupervised_btn.grid(row=3, sticky=NW)
672
- write_to_recent_project_paths(config_path=self.config_path)
673
-
674
- def create_video_info_table(self):
675
- video_info_tabler = VideoInfoTable(config_path=self.config_path)
676
- video_info_tabler.run()
677
-
678
- def initiate_skip_outlier_correction(self):
679
- outlier_correction_skipper = OutlierCorrectionSkipper(config_path=self.config_path)
680
- outlier_correction_skipper.run()
681
-
682
- def validate_model_first_step(self):
683
- _ = InferenceValidation(config_path=self.config_path, input_file_path=self.csvfile.file_path, clf_path=self.modelfile.file_path)
684
-
685
- def train_single_model(self, config_path=None):
686
- model_trainer = TrainRandomForestClassifier(config_path=config_path)
687
- model_trainer.run()
688
- model_trainer.save()
689
-
690
- def train_multiple_models_from_meta(self, config_path=None):
691
- model_trainer = GridSearchRandomForestClassifier(config_path=config_path)
692
- model_trainer.run()
693
-
694
- def importBoris(self):
695
- ann_folder = askdirectory()
696
- boris_appender = BorisAppender(config_path=self.config_path, data_dir=ann_folder)
697
- threading.Thread(target=boris_appender.run).start()
698
-
699
- def importSolomon(self):
700
- ann_folder = askdirectory()
701
- solomon_importer = SolomonImporter(config_path=self.config_path, data_dir=ann_folder)
702
- threading.Thread(target=solomon_importer.run).start()
703
-
704
- def import_ethovision(self):
705
- ann_folder = askdirectory()
706
- ethovision_importer = ImportEthovision(config_path=self.config_path, data_dir=ann_folder)
707
- threading.Thread(target=ethovision_importer.run).start()
708
-
709
- def import_deepethogram(self):
710
- ann_folder = askdirectory()
711
- deepethogram_importer = DeepEthogramImporter(config_path=self.config_path, data_dir=ann_folder)
712
- if self.core_cnt > Defaults.THREADSAFE_CORE_COUNT.value:
713
- deepethogram_importer.run()
714
- else:
715
- threading.Thread(target=deepethogram_importer.run).start()
716
-
717
- def import_noldus_observer(self):
718
- directory = askdirectory()
719
- noldus_observer_importer = NoldusObserverImporter(config_path=self.config_path, data_dir=directory)
720
- threading.Thread(target=noldus_observer_importer.run).start()
721
-
722
- def importMARS(self):
723
- bento_dir = askdirectory()
724
- bento_appender = BentoAppender(config_path=self.config_path, data_dir=bento_dir)
725
- threading.Thread(target=bento_appender.run).start()
726
-
727
- def launch_interactive_plot(self):
728
- interactive_grapher = InteractiveProbabilityGrapher(config_path=self.config_path,file_path=self.csvfile.file_path,model_path=self.modelfile.file_path)
729
- interactive_grapher.run()
730
-
731
- def generateSimBPlotlyFile(self, var):
732
- inputList = []
733
- for i in var:
734
- inputList.append(i.get())
735
- stdout_warning(msg="SimBA plotly interface is not available.")
736
- pass
737
-
738
- def open_plotly_interface(self, url):
739
- try:
740
- self.p.kill()
741
- self.p2.kill()
742
- except:
743
- print("Starting plotly")
744
- # get h5 file path and csv file path
745
- filePath, groupPath = self.plotly_file.file_path, self.groups_file.file_path
746
-
747
- # print file read
748
- if filePath.endswith(".h5"):
749
- print("Reading in", os.path.basename(filePath))
750
- elif groupPath.endswith(".csv"):
751
- print("Reading in", os.path.basename(groupPath))
752
-
753
- self.p = subprocess.Popen(
754
- [
755
- sys.executable,
756
- os.path.join(
757
- os.path.dirname(__file__), "dash_app", "SimBA_dash_app.py"
758
- ),
759
- filePath,
760
- groupPath,
761
- ]
762
- )
763
- # csvPath = os.path.join(os.path.dirname(self.config_path),'csv')
764
- # p = subprocess.Popen([sys.executable, r'simba\SimBA_dash_app.py', filePath, groupPath, csvPath])
765
- wait_for_internet_connection(url)
766
- self.p2 = subprocess.Popen(
767
- [
768
- sys.executable,
769
- os.path.join(
770
- os.path.dirname(__file__), "dash_app", "run_dash_tkinter.py"
771
- ),
772
- url,
773
- ]
774
- )
775
- subprocess_children = [self.p, self.p2]
776
- atexit.register(terminate_children, subprocess_children)
777
-
778
- def trainmachinemodelsetting(self):
779
- _ = MachineModelSettingsPopUp(config_path=self.config_path)
780
-
781
- def run_feature_extraction(self):
782
- print(f"Running feature extraction... start time: {get_current_time()}")
783
- feature_extractor_classes = get_bp_config_code_class_pairs()
784
- if self.user_defined_var.get():
785
- custom_feature_extractor = CustomFeatureExtractor(extractor_file_path=self.scriptfile.file_path,config_path=self.config_path)
786
- custom_feature_extractor.run()
787
- stdout_success(msg="Custom feature extraction complete!",source=self.__class__.__name__)
788
- else:
789
- print(f"Pose-estimation body part setting for feature extraction: {str(self.animal_cnt)} animals {str(self.pose_setting)} body-parts...")
790
- if self.pose_setting not in feature_extractor_classes.keys():
791
- raise InvalidInputError(msg=f"The project pose-configuration key is set to {self.pose_setting} which is invalid. OPTIONS: {list(feature_extractor_classes.keys())}. Check the pose-estimation setting in the project_config.ini", source=self.__class__.__name__)
792
- if self.pose_setting == "8":
793
- feature_extractor = feature_extractor_classes[self.pose_setting][self.animal_cnt](config_path=self.config_path)
794
- else:
795
- feature_extractor = feature_extractor_classes[self.pose_setting](config_path=self.config_path)
796
- feature_extractor.run()
797
-
798
- def set_distance_mm(self):
799
- check_int(name="DISTANCE IN MILLIMETER",value=self.distance_in_mm_eb.entry_get,min_value=1)
800
- self.config.set("Frame settings", "distance_mm", self.distance_in_mm_eb.entry_get)
801
- with open(self.config_path, "w") as f:
802
- self.config.write(f)
803
-
804
- def correct_outlier(self):
805
- outlier_correcter_movement = OutlierCorrecterMovement(config_path=self.config_path)
806
- outlier_correcter_movement.run()
807
- outlier_correcter_location = OutlierCorrecterLocation(config_path=self.config_path)
808
- outlier_correcter_location.run()
809
- stdout_success(msg='Outlier corrected files located in "project_folder/csv/outlier_corrected_movement_location" directory',source=self.__class__.__name__)
810
-
811
- def callback(self, url):
812
- webbrowser.open_new(url)
813
-
814
-
815
- class App(object):
816
- def __init__(self):
817
- bg_path = os.path.join(os.path.dirname(__file__), Paths.BG_IMG_PATH.value)
818
- emojis = get_emojis()
819
- icon_path_windows = os.path.join(os.path.dirname(__file__), Paths.LOGO_ICON_WINDOWS_PATH.value)
820
- icon_path_darwin = os.path.join(os.path.dirname(__file__), Paths.LOGO_ICON_DARWIN_PATH.value)
821
- self.menu_icons = get_icons_paths()
822
- recent_project_paths = get_recent_projects_paths()
823
- self.root = Tk()
824
- self.root.title("SimBA")
825
- self.root.minsize(750, 750)
826
- self.root.geometry(Formats.ROOT_WINDOW_SIZE.value)
827
- self.root.rowconfigure(0, weight=1)
828
- self.root.columnconfigure(0, weight=1)
829
- if currentPlatform == OS.WINDOWS.value:
830
- load_simba_fonts()
831
- self.root.iconbitmap(icon_path_windows)
832
- if currentPlatform == OS.MAC.value:
833
- load_simba_fonts()
834
- self.root.iconphoto(False, ImageTk.PhotoImage(PIL.Image.open(icon_path_darwin)))
835
- for k in self.menu_icons.keys():
836
- self.menu_icons[k]["img"] = ImageTk.PhotoImage(image=PIL.Image.open(os.path.join(os.path.dirname(__file__), self.menu_icons[k]["icon_path"])))
837
- bg_img = ImageTk.PhotoImage(file=bg_path)
838
- background = Label(self.root, image=bg_img, bd=0, bg="white")
839
- background.pack(fill="both", expand=True)
840
- background.image = bg_img
841
-
842
- ultralytics_version = get_pkg_version(pkg=PackageNames.ULTRALYTICS.value)
843
- yolo_state = DISABLED if ultralytics_version is None else NORMAL
844
-
845
-
846
- menu = Menu(self.root)
847
- self.root.config(menu=menu)
848
- self.file_menu = Menu(menu)
849
- menu.add_cascade(label="File", menu=self.file_menu)
850
- self.file_menu.add_command(label="Create a new project", compound="left", image=self.menu_icons["create"]["img"], command=lambda: ProjectCreatorPopUp(), font=Formats.FONT_REGULAR.value)
851
- self.file_menu.add_command(label="Load project", compound="left", image=self.menu_icons["load"]["img"], command=lambda: LoadProjectPopUp(), font=Formats.FONT_REGULAR.value)
852
- self.file_menu.add_separator()
853
- self.recent_projects_menu = Menu(menu)
854
-
855
- for recent_project_path in recent_project_paths:
856
- self.recent_projects_menu.add_command(label=recent_project_path,command=lambda p=recent_project_path: SimbaProjectPopUp(config_path=p), font=Formats.FONT_REGULAR.value)
857
- self.recent_projects_menu.add_command(label='Clear recent projects', command=lambda: self.clear_recent_projects(), font=Formats.FONT_REGULAR_ITALICS.value)
858
- recent_project_state = DISABLED if len(recent_project_paths) == 0 else NORMAL
859
- self.file_menu.add_cascade(label="Open recent project...", compound="left", image=self.menu_icons["recent_files"]["img"], menu=self.recent_projects_menu, font=Formats.FONT_REGULAR.value, state=recent_project_state)
860
-
861
- self.file_menu.add_separator()
862
- self.file_menu.add_command(label="Restart", compound="left", image=self.menu_icons["restart"]["img"], command=lambda: self.restart(), font=Formats.FONT_REGULAR.value)
863
- self.file_menu.add_separator()
864
- self.file_menu.add_command(label="Exit", compound="left", image=self.menu_icons["exit"]["img"], command=self.root.destroy, font=Formats.FONT_REGULAR.value)
865
-
866
- batch_process_menu = Menu(menu)
867
- menu.add_cascade(label="Process Videos", menu=batch_process_menu)
868
- batch_process_menu.add_command(label="Batch pre-process videos", compound="left", image=self.menu_icons["factory"]["img"], command=lambda: BatchPreProcessPopUp(), font=Formats.FONT_REGULAR.value)
869
-
870
- blob_tracking_menu = Menu(batch_process_menu)
871
- blob_tracking_menu.add_command(label="Perform blob tracking", compound="left", image=self.menu_icons["bubble_green"]["img"], command=InitializeBlobTrackerPopUp, font=Formats.FONT_REGULAR.value)
872
- blob_tracking_menu.add_command(label="Visualize blob tracking", compound="left", image=self.menu_icons["bubble_pink"]["img"], command=BlobVisualizerPopUp, font=Formats.FONT_REGULAR.value)
873
- batch_process_menu.add_cascade(label="Blob tracking...", compound="left", image=self.menu_icons["bubble"]["img"], menu=blob_tracking_menu, font=Formats.FONT_REGULAR.value)
874
-
875
- yolo_tracking_menu = Menu(batch_process_menu)
876
- yolo_tracking_menu.add_command(label="Train YOLO model", compound="left", image=self.menu_icons["ultralytics_2"]["img"], command=YOLOPoseTrainPopUP, font=Formats.FONT_REGULAR.value, state=yolo_state)
877
- yolo_tracking_menu.add_command(label="Predict with YOLO model", compound="left", image=self.menu_icons["ultralytics_2"]["img"], command=YOLOPoseInferencePopUP, font=Formats.FONT_REGULAR.value, state=yolo_state)
878
- yolo_tracking_menu.add_command(label="Visualize YOLO model results", compound="left", image=self.menu_icons["ultralytics_2"]["img"], command=YoloPoseVisualizerPopUp, font=Formats.FONT_REGULAR.value, state=yolo_state)
879
- batch_process_menu.add_cascade(label="YOLO tracking...", compound="left", image=self.menu_icons["ultralytics_2"]["img"], menu=yolo_tracking_menu, font=Formats.FONT_REGULAR.value, state=yolo_state)
880
-
881
- video_process_menu = Menu(menu)
882
- fps_menu = Menu(video_process_menu)
883
- fps_menu.add_command(label="Change FPS for single video", compound="left", image=self.menu_icons["single_blue"]["img"], command=ChangeFpsSingleVideoPopUp, font=Formats.FONT_REGULAR.value)
884
- fps_menu.add_command(label="Change FPS for multiple videos", compound="left", image=self.menu_icons["multiple_blue"]["img"], command=ChangeFpsMultipleVideosPopUp, font=Formats.FONT_REGULAR.value)
885
- fps_menu.add_command(label="Up-sample fps with interpolation", command=UpsampleVideosPopUp, font=Formats.FONT_REGULAR.value)
886
-
887
- menu.add_cascade(label="Tools", menu=video_process_menu)
888
- video_process_menu.add_cascade(label="Change FPS...", compound="left", image=self.menu_icons["fps"]["img"], menu=fps_menu, font=Formats.FONT_REGULAR.value)
889
-
890
- clip_video_menu = Menu(menu)
891
- clip_video_menu.add_command(label="Clip single video", command=ClipVideoPopUp, font=Formats.FONT_REGULAR.value, image=self.menu_icons["video_2"]["img"], compound="left",)
892
- clip_video_menu.add_command(label="Clip multiple videos", command=InitiateClipMultipleVideosByTimestampsPopUp, font=Formats.FONT_REGULAR.value, image=self.menu_icons["stack"]["img"], compound="left",)
893
-
894
- clip_video_menu.add_command(label="Clip video into multiple videos", command=MultiShortenPopUp, font=Formats.FONT_REGULAR.value, image=self.menu_icons["one_to_many"]["img"], compound="left",)
895
- clip_video_menu.add_command(label="Clip single video by frame numbers", command=ClipSingleVideoByFrameNumbers, font=Formats.FONT_REGULAR.value, image=self.menu_icons["video_2"]["img"], compound="left",)
896
- clip_video_menu.add_command(label="Clip multiple videos by frame numbers", command=InitiateClipMultipleVideosByFrameNumbersPopUp, font=Formats.FONT_REGULAR.value, image=self.menu_icons["stack"]["img"], compound="left",)
897
-
898
- video_process_menu.add_cascade(label="Clip videos...", compound="left", image=self.menu_icons["clip"]["img"], menu=clip_video_menu, font=Formats.FONT_REGULAR.value)
899
-
900
- crop_video_menu = Menu(menu)
901
- crop_video_menu.add_command(label="Crop videos", compound="left", image=self.menu_icons["crop"]["img"], command=CropVideoPopUp, font=Formats.FONT_REGULAR.value)
902
- crop_video_menu.add_command(label="Crop videos (circles)", compound="left", image=self.menu_icons["circle"]["img"], command=CropVideoCirclesPopUp, font=Formats.FONT_REGULAR.value)
903
- crop_video_menu.add_command(label="Crop videos (polygons)", compound="left", image=self.menu_icons["polygon"]["img"], command=CropVideoPolygonsPopUp, font=Formats.FONT_REGULAR.value)
904
- crop_video_menu.add_command(label="Multi-crop", compound="left", image=self.menu_icons["crop"]["img"], command=MultiCropPopUp, font=Formats.FONT_REGULAR.value)
905
- video_process_menu.add_cascade(label="Crop videos...", compound="left", image=self.menu_icons["crop"]["img"], menu=crop_video_menu, font=Formats.FONT_REGULAR.value)
906
-
907
- format_menu = Menu(video_process_menu)
908
- img_format_menu = Menu(format_menu)
909
- video_format_menu = Menu(format_menu)
910
-
911
-
912
-
913
- img_format_menu.add_command(label="Convert images to PNG", compound="left", image=self.menu_icons["png"]["img"], command=Convert2PNGPopUp, font=Formats.FONT_REGULAR.value)
914
- img_format_menu.add_command(label="Convert images to JPEG", compound="left", image=self.menu_icons["jpeg"]["img"], command=Convert2jpegPopUp, font=Formats.FONT_REGULAR.value)
915
- img_format_menu.add_command(label="Convert images to BMP", compound="left", image=self.menu_icons["bmp"]["img"], command=Convert2bmpPopUp, font=Formats.FONT_REGULAR.value)
916
- img_format_menu.add_command(label="Convert images to TIFF", compound="left", image=self.menu_icons["tiff"]["img"], command=Convert2TIFFPopUp, font=Formats.FONT_REGULAR.value)
917
- img_format_menu.add_command(label="Convert images to WEBP", compound="left", image=self.menu_icons["webp"]["img"], command=Convert2WEBPPopUp, font=Formats.FONT_REGULAR.value)
918
- video_format_menu.add_command(label="Convert videos to MP4", compound="left", image=self.menu_icons["mp4"]["img"], command=Convert2MP4PopUp, font=Formats.FONT_REGULAR.value)
919
- video_format_menu.add_command(label="Convert videos to AVI", compound="left", image=self.menu_icons["avi"]["img"], command=Convert2AVIPopUp, font=Formats.FONT_REGULAR.value)
920
- video_format_menu.add_command(label="Convert videos to WEBM", compound="left", image=self.menu_icons["webm"]["img"], command=Convert2WEBMPopUp, font=Formats.FONT_REGULAR.value)
921
- video_format_menu.add_command(label="Convert videos to MOV", compound="left", image=self.menu_icons["mov"]["img"], command=Convert2MOVPopUp, font=Formats.FONT_REGULAR.value)
922
- format_menu.add_cascade(label="Convert image file formats...", compound="left", image=self.menu_icons["image"]["img"], menu=img_format_menu, font=Formats.FONT_REGULAR.value)
923
- format_menu.add_cascade(label="Change video file formats...", compound="left", image=self.menu_icons["video_2"]["img"], menu=video_format_menu, font=Formats.FONT_REGULAR.value)
924
- video_process_menu.add_cascade(label="Convert file formats...", compound="left", image=self.menu_icons["convert"]["img"], menu=format_menu, font=Formats.FONT_REGULAR.value)
925
-
926
- rm_clr_menu = Menu(video_process_menu)
927
- rm_clr_menu.add_command(label="Convert to grayscale", compound="left", image=self.menu_icons["greyscale"]["img"], command=lambda: GreyscaleSingleVideoPopUp(), font=Formats.FONT_REGULAR.value)
928
- rm_clr_menu.add_command(label="Convert to black and white", compound="left", image=self.menu_icons["bw"]["img"], command=Convert2BlackWhitePopUp, font=Formats.FONT_REGULAR.value)
929
- rm_clr_menu.add_command(label="CLAHE enhance videos", compound="left", image=self.menu_icons["clahe"]["img"], command=CLAHEPopUp, font=Formats.FONT_REGULAR.value)
930
- rm_clr_menu.add_command(label="Interactively CLAHE enhance videos", compound="left", image=self.menu_icons["clahe"]["img"], command=InteractiveClahePopUp, font=Formats.FONT_REGULAR.value)
931
- video_process_menu.add_cascade(label="Remove color from videos...", compound="left", image=self.menu_icons["clahe"]["img"], menu=rm_clr_menu, font=Formats.FONT_REGULAR.value)
932
-
933
- concatenate_menu = Menu(video_process_menu)
934
- concatenate_menu.add_command(label="Concatenate two videos", compound="left", image=self.menu_icons["concat"]["img"], command=ConcatenatingVideosPopUp, font=Formats.FONT_REGULAR.value)
935
- concatenate_menu.add_command(label="Concatenate multiple videos", compound="left", image=self.menu_icons["concat_videos"]["img"], command=lambda: ConcatenatorPopUp(config_path=None), font=Formats.FONT_REGULAR.value)
936
- video_process_menu.add_cascade(label="Concatenate (stack) videos...", compound="left", image=self.menu_icons["concat"]["img"], menu=concatenate_menu, font=Formats.FONT_REGULAR.value)
937
- video_process_menu.add_command(label="Convert ROI definitions", compound="left", image=self.menu_icons["roi"]["img"], command=lambda: ConvertROIDefinitionsPopUp(), font=Formats.FONT_REGULAR.value)
938
-
939
- convert_pose_file_format_menu = Menu(video_process_menu)
940
- convert_pose_file_format_menu.add_command(label="COCO key-points -> YOLO key-points", compound="left", image=self.menu_icons["coco_small"]["img"], command=COCOKeypoints2YOLOkeypointsPopUp, font=Formats.FONT_REGULAR.value)
941
- convert_pose_file_format_menu.add_command(label="COCO key-point files (multiple) -> COCO key-point file (single)", compound="left", image=self.menu_icons["coco_small"]["img"], command=MergeCOCOKeypointFilesPopUp, font=Formats.FONT_REGULAR.value)
942
- convert_pose_file_format_menu.add_command(label="DLC annotations -> Labelme key-points", compound="left", image=self.menu_icons["dlc_2"]["img"], command=DLC2LabelmePopUp, font=Formats.FONT_REGULAR.value)
943
- convert_pose_file_format_menu.add_command(label="DLC annotations -> YOLO pose-estimation annotations", compound="left", image=self.menu_icons["dlc_2"]["img"], command=DLCYoloKeypointsPopUp, font=Formats.FONT_REGULAR.value)
944
- convert_pose_file_format_menu.add_command(label="DLC H5 inference -> YOLO pose-estimation annotations", compound="left", image=self.menu_icons["dlc_2"]["img"], command=DLCH5Inference2YoloPopUp, font=Formats.FONT_REGULAR.value)
945
- convert_pose_file_format_menu.add_command(label="SLEAP CSV inference -> YOLO pose-estimation annotations", compound="left", image=self.menu_icons["sleap_small"]["img"], command=SLEAPcsvInference2Yolo, font=Formats.FONT_REGULAR.value)
946
- convert_pose_file_format_menu.add_command(label="SLEAP H5 inference -> YOLO pose-estimation annotations", compound="left", image=self.menu_icons["sleap_small"]["img"], command=SLEAPH5Inference2YoloPopUp, font=Formats.FONT_REGULAR.value)
947
- convert_pose_file_format_menu.add_command(label="SLEAP SLP annotations -> YOLO pose-estimation annotations", compound="left", image=self.menu_icons["sleap_small"]["img"], command=SLEAPAnnotations2YoloPopUp, font=Formats.FONT_REGULAR.value)
948
- convert_pose_file_format_menu.add_command(label="SimBA ROI -> YOLO bounding-box annotations", compound="left", image=self.menu_icons["SimBA_logo_3_small"]["img"], command=SimBAROIs2YOLOPopUp, font=Formats.FONT_REGULAR.value)
949
- convert_pose_file_format_menu.add_command(label="SimBA -> YOLO pose-estimation annotations", compound="left", image=self.menu_icons["SimBA_logo_3_small"]["img"], command=SimBA2YoloKeypointsPopUp, font=Formats.FONT_REGULAR.value)
950
- convert_pose_file_format_menu.add_command(label="Labelme key-points -> Images", compound="left", image=self.menu_icons["labelme"]["img"], command=Labelme2ImgsPopUp, font=Formats.FONT_REGULAR.value)
951
- convert_pose_file_format_menu.add_command(label="Labelme key-points -> CSV", compound="left", image=self.menu_icons["labelme"]["img"], command=Labelme2DataFramePopUp, font=Formats.FONT_REGULAR.value)
952
- convert_pose_file_format_menu.add_command(label="Labelme bounding-boxes -> YOLO bounding-box annotations", compound="left", image=self.menu_icons["labelme"]["img"], command=LabelmeBbox2YoloBboxPopUp, font=Formats.FONT_REGULAR.value)
953
-
954
- video_process_menu.add_cascade(label="Convert tracking data formats...", compound="left", image=self.menu_icons["pose"]["img"], menu=convert_pose_file_format_menu, font=Formats.FONT_REGULAR.value)
955
-
956
- convert_data_menu = Menu(video_process_menu)
957
- convert_data_menu.add_command(label="Convert CSV to parquet", compound="left", image=self.menu_icons["parquet"]["img"], command=Csv2ParquetPopUp, font=Formats.FONT_REGULAR.value)
958
- convert_data_menu.add_command(label="Convert parquet to CSV", compound="left", image=self.menu_icons["csv_grey"]["img"], command=Parquet2CsvPopUp, font=Formats.FONT_REGULAR.value)
959
- video_process_menu.add_cascade(label="Convert working file type...", compound="left", image=self.menu_icons["change"]["img"], menu=convert_data_menu, font=Formats.FONT_REGULAR.value)
960
- video_process_menu.add_command(label="Create path plot", compound="left", image=self.menu_icons["path"]["img"], command=MakePathPlotPopUp, font=Formats.FONT_REGULAR.value)
961
-
962
- downsample_video_menu = Menu(video_process_menu)
963
- downsample_video_menu.add_command(label="Down-sample single video", compound="left", image=self.menu_icons["single_green"]["img"], command=DownsampleSingleVideoPopUp, font=Formats.FONT_REGULAR.value)
964
- downsample_video_menu.add_command(label="Down-sample multiple videos", compound="left", image=self.menu_icons["multiple_green"]["img"], command=DownsampleMultipleVideosPopUp, font=Formats.FONT_REGULAR.value)
965
- video_process_menu.add_cascade(label="Down-sample video...", compound="left", image=self.menu_icons["sample"]["img"], menu=downsample_video_menu, font=Formats.FONT_REGULAR.value)
966
- video_process_menu.add_cascade(label="Drop body-parts from tracking data", compound="left", image=self.menu_icons["trash"]["img"], command=DropTrackingDataPopUp, font=Formats.FONT_REGULAR.value)
967
- extract_frames_menu = Menu(video_process_menu, font=Formats.FONT_REGULAR.value)
968
- extract_frames_menu.add_command(label="Extract defined frames", command=ExtractSpecificFramesPopUp, font=Formats.FONT_REGULAR.value, image=self.menu_icons["frames"]["img"], compound="left")
969
- extract_frames_menu.add_command(label="Extract frames from single video", command=SingleVideo2FramesPopUp, font=Formats.FONT_REGULAR.value, image=self.menu_icons["frames_2"]["img"], compound="left")
970
- extract_frames_menu.add_command(label="Extract frames from multiple videos", command=MultipleVideos2FramesPopUp, font=Formats.FONT_REGULAR.value, image=self.menu_icons["stack"]["img"], compound="left")
971
- extract_frames_menu.add_command(label="Extract frames from seq files", command=ExtractSEQFramesPopUp, font=Formats.FONT_REGULAR.value, image=self.menu_icons["fire"]["img"], compound="left")
972
- video_process_menu.add_cascade(label="Extract frames...", compound="left", image=self.menu_icons["frames"]["img"], menu=extract_frames_menu, font=Formats.FONT_REGULAR.value)
973
-
974
- video_process_menu.add_command(label="Create GIFs", compound="left", image=self.menu_icons["gif"]["img"], command=CreateGIFPopUP, font=Formats.FONT_REGULAR.value)
975
-
976
- video_process_menu.add_command(label="Get metric conversion factor (pixels/millimeter)", compound="left", image=self.menu_icons["calipher"]["img"], command=CalculatePixelsPerMMInVideoPopUp, font=Formats.FONT_REGULAR.value)
977
- video_process_menu.add_command(label="Change video brightness / contrast", compound="left", image=self.menu_icons["brightness"]["img"], command=BrightnessContrastPopUp, font=Formats.FONT_REGULAR.value)
978
- video_process_menu.add_command(label="Merge frames to video", compound="left", image=self.menu_icons["merge"]["img"], command=MergeFrames2VideoPopUp, font=Formats.FONT_REGULAR.value)
979
- video_process_menu.add_command(label="Change video playback speed", compound="left", image=self.menu_icons["run"]["img"], command=ChangeSpeedPopup, font=Formats.FONT_REGULAR.value)
980
- video_process_menu.add_command(label="Print classifier info", compound="left", image=self.menu_icons["print"]["img"], command=PrintModelInfoPopUp, font=Formats.FONT_REGULAR.value)
981
- video_process_menu.add_command(label="Show video file(s) meta data", compound="left", image=self.menu_icons["print"]["img"], command=PrintVideoMetaDataPopUp, font=Formats.FONT_REGULAR.value)
982
-
983
-
984
- video_process_menu.add_cascade(label="Reorganize Tracking Data", compound="left", image=self.menu_icons["reorganize"]["img"], command=PoseReorganizerPopUp, font=Formats.FONT_REGULAR.value)
985
-
986
- rotate_menu = Menu(menu)
987
- rotate_menu.add_command(label="Rotate videos", compound="left", image=self.menu_icons["flip_red"]["img"], command=RotateVideoSetDegreesPopUp, font=Formats.FONT_REGULAR.value)
988
- rotate_menu.add_command(label="Interactively rotate videos", compound="left", image=self.menu_icons["flip_red"]["img"], command=VideoRotatorPopUp, font=Formats.FONT_REGULAR.value)
989
- rotate_menu.add_command(label="Flip videos", compound="left", image=self.menu_icons["flip_green"]["img"], command=FlipVideosPopUp, font=Formats.FONT_REGULAR.value)
990
- rotate_menu.add_command(label="Reverse videos", compound="left", image=self.menu_icons["reverse_blue"]["img"], command=ReverseVideoPopUp, font=Formats.FONT_REGULAR.value)
991
- video_process_menu.add_cascade(label="Rotate / flip / reverse videos...", compound="left", image=self.menu_icons["rotate"]["img"], menu=rotate_menu, font=Formats.FONT_REGULAR.value)
992
-
993
- superimpose_menu = Menu(menu)
994
- superimpose_menu.add_command(label="Superimpose frame numbers", compound="left", image=self.menu_icons["number_black"]["img"], command=SuperImposeFrameCountPopUp, font=Formats.FONT_REGULAR.value)
995
- superimpose_menu.add_command(label="Superimpose watermark", compound="left", image=self.menu_icons["watermark_green"]["img"], command=SuperimposeWatermarkPopUp, font=Formats.FONT_REGULAR.value)
996
- superimpose_menu.add_command(label="Superimpose timer", compound="left", image=self.menu_icons["timer"]["img"], command=SuperimposeTimerPopUp, font=Formats.FONT_REGULAR.value)
997
- superimpose_menu.add_command(label="Superimpose progress-bar", compound="left", image=self.menu_icons["progressbar_black"]["img"], command=SuperimposeProgressBarPopUp, font=Formats.FONT_REGULAR.value)
998
- superimpose_menu.add_command(label="Superimpose video on video", compound="left", image=self.menu_icons["video_2"]["img"], command=SuperimposeVideoPopUp, font=Formats.FONT_REGULAR.value)
999
- superimpose_menu.add_command(label="Superimpose video names", compound="left", image=self.menu_icons["id_card"]["img"], command=SuperimposeVideoNamesPopUp, font=Formats.FONT_REGULAR.value)
1000
- superimpose_menu.add_command(label="Superimpose free-text", compound="left", image=self.menu_icons["text_black"]["img"], command=SuperimposeTextPopUp, font=Formats.FONT_REGULAR.value)
1001
- video_process_menu.add_cascade(label="Superimpose on videos...", compound="left", image=self.menu_icons["superimpose"]["img"], menu=superimpose_menu, font=Formats.FONT_REGULAR.value)
1002
-
1003
- remove_bg_menu = Menu(menu)
1004
- remove_bg_menu.add_command(label="Remove background from single video (mean subtraction)", compound="left", image=self.menu_icons["remove_bg"]["img"], command=BackgroundRemoverSingleVideoPopUp, font=Formats.FONT_REGULAR.value)
1005
- remove_bg_menu.add_command(label="Remove background from multiple videos (mean subtraction)", compound="left", image=self.menu_icons["remove_bg"]["img"], command=BackgroundRemoverDirectoryPopUp, font=Formats.FONT_REGULAR.value)
1006
- video_process_menu.add_cascade(label="Remove video backgrounds...", compound="left", image=self.menu_icons["remove_bg"]["img"], menu=remove_bg_menu, font=Formats.FONT_REGULAR.value)
1007
-
1008
- temporal_join_videos = Menu(menu)
1009
- temporal_join_videos.add_command(label="Temporal join all videos in directory", command=VideoTemporalJoinPopUp, font=Formats.FONT_REGULAR.value)
1010
- temporal_join_videos.add_command(label="Temporal join selected videos", command=ManualTemporalJoinPopUp, font=Formats.FONT_REGULAR.value)
1011
- video_process_menu.add_cascade(label="Temporal join videos...", compound="left", image=self.menu_icons["stopwatch"]["img"], menu=temporal_join_videos, font=Formats.FONT_REGULAR.value)
1012
- video_process_menu.add_command(label="Box blur videos", compound="left", image=self.menu_icons["blur"]["img"], command=BoxBlurPopUp, font=Formats.FONT_REGULAR.value)
1013
- video_process_menu.add_command(label="Cross-fade videos", compound="left", image=self.menu_icons["crossfade"]["img"], command=CrossfadeVideosPopUp, font=Formats.FONT_REGULAR.value)
1014
- video_process_menu.add_command(label="Create average frames from videos", compound="left", image=self.menu_icons["average"]["img"], command=CreateAverageFramePopUp, font=Formats.FONT_REGULAR.value)
1015
- video_process_menu.add_command(label="Validate video seekability", compound="left", image=self.menu_icons["search"]["img"], command=CheckVideoSeekablePopUp, font=Formats.FONT_REGULAR.value)
1016
- video_process_menu.add_command(label="Visualize pose-estimation in folder...", compound="left", image=self.menu_icons["visualize"]["img"], command=VisualizePoseInFolderPopUp, font=Formats.FONT_REGULAR.value)
1017
-
1018
- help_menu = Menu(menu)
1019
- menu.add_cascade(label="Help", menu=help_menu)
1020
- links_menu = Menu(help_menu)
1021
- download_menu = Menu(links_menu)
1022
- download_menu.add_command(label="Download weights", compound="left", image=self.menu_icons["dumbbell"]["img"], command=lambda: webbrowser.open_new(str(r"https://osf.io/sr3ck/")), font=Formats.FONT_REGULAR.value)
1023
- download_menu.add_command(label="Download data/classifiers", compound="left", image=self.menu_icons["osf"]["img"], command=lambda: webbrowser.open_new(str(r"https://osf.io/kwge8/")), font=Formats.FONT_REGULAR.value)
1024
-
1025
- yolo_links = Menu(download_menu)
1026
- for mdl_name, mdl_link in Links.YOLO_11_WEIGHTS.value.items():
1027
- yolo_links.add_command(label=mdl_name, compound="left", image=self.menu_icons["ultralytics_2"]["img"], command=lambda: webbrowser.open_new(str({mdl_link})), font=Formats.FONT_REGULAR.value)
1028
-
1029
- download_menu.add_cascade(label="YOLO weights...", compound="left", image=self.menu_icons["ultralytics_2"]["img"], menu=yolo_links, font=Formats.FONT_REGULAR.value)
1030
- links_menu.add_cascade(label="Download...", compound="left", image=self.menu_icons["download"]["img"], menu=download_menu, font=Formats.FONT_REGULAR.value)
1031
- links_menu.add_command(label="SimBA Github", compound="left", image=self.menu_icons["github"]["img"], command=lambda: webbrowser.open_new(str(r"https://github.com/sgoldenlab/simba")), font=Formats.FONT_REGULAR.value)
1032
- links_menu.add_command(label="SimBA Gitter Support Chatroom", compound="left", image=self.menu_icons["gitter"]["img"], command=lambda: webbrowser.open_new(str(r"https://gitter.im/SimBA-Resource/community")), font=Formats.FONT_REGULAR.value)
1033
- links_menu.add_command(label="Install FFmpeg", compound="left", image=self.menu_icons["ffmpeg"]["img"], command=lambda: webbrowser.open_new(str(r"https://m.wikihow.com/Install-FFmpeg-on-Windows")), font=Formats.FONT_REGULAR.value)
1034
- links_menu.add_command(label="SimBA API", compound="left", image=self.menu_icons["api"]["img"], command=lambda: webbrowser.open_new(str(r"https://simba-uw-tf-dev.readthedocs.io/")), font=Formats.FONT_REGULAR.value)
1035
- links_menu.add_command(label="SimBA usage statistics", compound="left", image=self.menu_icons["line_chart_light_blue"]["img"], command=lambda: webbrowser.open_new(str(r"https://sronilsson.github.io/download_stats/")), font=Formats.FONT_REGULAR.value)
1036
- links_menu.add_command(label="SimBA developer contact", compound="left", image=self.menu_icons["developer"]["img"], command=lambda: webbrowser.open_new(str(r"https://sronilsson.netlify.app/")), font=Formats.FONT_REGULAR.value)
1037
-
1038
- help_menu.add_cascade(label="Links", menu=links_menu, compound="left", image=self.menu_icons["link"]["img"], font=Formats.FONT_REGULAR.value)
1039
- help_menu.add_command(label="Check for updates", compound="left", image=self.menu_icons["download"]["img"], command=check_for_updates, font=Formats.FONT_REGULAR.value)
1040
- help_menu.add_command(label="About", compound="left", image=self.menu_icons["about"]["img"], command=AboutSimBAPopUp, font=Formats.FONT_REGULAR.value)
1041
-
1042
- self.frame = Frame(background, bd=2, relief=SUNKEN, width=750, height=300)
1043
- self.r_click_menu = Menu(self.root, tearoff=0)
1044
- self.r_click_menu.add_command(label="Copy selection", command=lambda: self.copy_selection_to_clipboard(), font=Formats.FONT_REGULAR.value)
1045
- self.r_click_menu.add_command(label="Copy all", command=lambda: self.copy_all_to_clipboard(), font=Formats.FONT_REGULAR.value)
1046
- self.r_click_menu.add_command(label="Paste", command=lambda: self.paste_to_txt(), font=Formats.FONT_REGULAR.value)
1047
- self.r_click_menu.add_separator()
1048
- self.r_click_menu.add_command(label="Clear", command=lambda: self.clean_txt(), font=Formats.FONT_REGULAR.value)
1049
- y_sb = Scrollbar(self.frame, orient=VERTICAL)
1050
- self.frame.pack(expand=True)
1051
- self.txt = Text(self.frame, bg="white", insertborderwidth=2, height=30, width=100, yscrollcommand=y_sb)
1052
- if currentPlatform == OS.WINDOWS.value: self.txt.bind("<Button-3>", self.show_right_click_pop_up)
1053
- elif currentPlatform == OS.MAC.value: self.txt.bind("<Button-2>", self.show_right_click_pop_up)
1054
- self.txt.tag_configure(TagNames.GREETING.value, justify="center", foreground="blue", font=Formats.FONT_LARGE_BOLD.value)
1055
- self.txt.tag_configure(TagNames.ERROR.value, justify="left", foreground="red", font=Formats.FONT_REGULAR.value)
1056
- self.txt.tag_configure(TagNames.STANDARD.value, justify="left", foreground="black", font=Formats.FONT_REGULAR.value)
1057
- self.txt.tag_configure(TagNames.COMPLETE.value, justify="left", foreground="darkgreen", font=Formats.FONT_REGULAR_BOLD.value)
1058
- self.txt.tag_configure(TagNames.WARNING.value, justify="left", foreground="darkorange", font=Formats.FONT_REGULAR.value)
1059
- self.txt.tag_configure(TagNames.INFORMATION.value, justify="left", foreground="blue", font=Formats.FONT_REGULAR.value)
1060
- self.txt.tag_configure("TABLE", foreground="darkorange", font=Formats.FONT_REGULAR.value, wrap="none", borderwidth=0)
1061
- if ENV[ENV_VARS.PRINT_EMOJIS.value]:
1062
- self.txt.insert(INSERT, Defaults.WELCOME_MSG.value + emojis["relaxed"] + "\n" * 2)
1063
- else:
1064
- self.txt.insert(INSERT, Defaults.WELCOME_MSG.value + "\n" * 2)
1065
- self.txt.tag_add(TagNames.GREETING.value, "1.0", "3.25")
1066
- y_sb.pack(side=RIGHT, fill=Y)
1067
- self.txt.pack(expand=True, fill="both")
1068
- y_sb.config(command=self.txt.yview)
1069
- self.txt.config(state=DISABLED, font=Formats.FONT_REGULAR.value)
1070
-
1071
- clear_txt_btn = SimbaButton(parent=self.frame, txt=" CLEAR", txt_clr='blue', img='clean', cmd=self.clean_txt, font=Formats.FONT_HEADER.value, anchor='center', hover_font=Formats.FONT_HEADER.value)
1072
- clear_txt_btn.pack(side=BOTTOM, fill=X)
1073
- sys.stdout = StdRedirector(self.txt)
1074
-
1075
- if OS.PYTHON_VER.value != "3.6":
1076
- self.txt['width'], self.txt['height'] = 200, 38
1077
- PythonVersionWarning(msg=f"SimBA is not extensively tested beyond python 3.6. You are using python {OS.PYTHON_VER.value}. If you encounter errors in python>3.6, please report them on GitHub or Gitter (links in the help toolbar) and we will work together to fix the issues!", source=self.__class__.__name__)
1078
-
1079
- if not check_ffmpeg_available():
1080
- FFMpegNotFoundWarning(msg='SimBA could not find a FFMPEG installation on computer (as evaluated by "ffmpeg" returning None). SimBA works best with FFMPEG and it is recommended to install it on your computer', source=self.__class__.__name__)
1081
-
1082
-
1083
-
1084
-
1085
- simba_pip_data = fetch_pip_data(pip_url=Links.SIMBA_PIP_URL.value)
1086
- if (simba_pip_data[1] is not None) and OS.SIMBA_VERSION.value is not None:
1087
- if simba_pip_data[1] != OS.SIMBA_VERSION.value:
1088
- msg = f"A new version of SimBA is available: {simba_pip_data[1]} (you have version {OS.SIMBA_VERSION.value}). Consider upgrading using: pip install simba-uw-tf-dev --upgrade"
1089
- VersionWarning(msg=msg)
1090
-
1091
- def clear_recent_projects(self):
1092
- file_path = os.path.join(os.path.dirname(__file__), Paths.RECENT_PROJECTS_PATHS.value)
1093
- remove_files(file_paths=[file_path], raise_error=False)
1094
- self.recent_projects_menu.delete(0, self.recent_projects_menu.index('end') - 1)
1095
- self.file_menu.entryconfig("Open recent project...", state=DISABLED)
1096
-
1097
-
1098
-
1099
- def restart(self):
1100
- confirm_restart = askyesno(title="RESTART", message="Are you sure that you want restart SimBA?")
1101
- if confirm_restart:
1102
- self.root.destroy()
1103
- os.execl(sys.executable, sys.executable, *sys.argv)
1104
-
1105
- def clean_txt(self):
1106
- self.txt.config(state=NORMAL)
1107
- self.txt.delete("1.0", END)
1108
-
1109
- def show_right_click_pop_up(self, event):
1110
- try:
1111
- self.r_click_menu.tk_popup(event.x_root, event.y_root)
1112
- finally:
1113
- self.r_click_menu.grab_release()
1114
-
1115
- def copy_selection_to_clipboard(self):
1116
- self.root.clipboard_clear()
1117
- text = self.txt.get("sel.first", "sel.last")
1118
- text = text.encode("ascii", "ignore").decode()
1119
- self.root.clipboard_append(text)
1120
-
1121
- def copy_all_to_clipboard(self):
1122
- self.root.clipboard_clear()
1123
- self.root.clipboard_append(self.txt.get("1.0", "end-1c"))
1124
-
1125
- def paste_to_txt(self):
1126
- try:
1127
- print(self.root.clipboard_get())
1128
- except UnicodeDecodeError:
1129
- raise InvalidInputError(
1130
- msg="Can only paste utf-8 compatible text",
1131
- source=self.__class__.__name__,
1132
- )
1133
-
1134
-
1135
- class StdRedirector(object):
1136
- def __init__(self, text_widget):
1137
- self.text_space = text_widget
1138
- self.emojis = get_emojis()
1139
-
1140
- def write(self, s: str):
1141
- tag_name = TagNames.STANDARD.value
1142
- try:
1143
- s, tag_name = s.split(Defaults.STR_SPLIT_DELIMITER.value, 2)
1144
- except ValueError:
1145
- pass
1146
- if (tag_name != TagNames.STANDARD.value) and (tag_name != "TABLE"):
1147
- if ENV[ENV_VARS.PRINT_EMOJIS.value]:
1148
- s = s + " " + self.emojis[tag_name]
1149
- else:
1150
- pass
1151
- self.text_space.config(state=NORMAL)
1152
- self.text_space.insert("end", s, (tag_name))
1153
- self.text_space.update()
1154
- self.text_space.see("end")
1155
- self.text_space.config(state=DISABLED)
1156
-
1157
- def flush(self):
1158
- pass
1159
-
1160
- def terminate_children(children):
1161
- for process in children:
1162
- process.terminate()
1163
-
1164
- def main():
1165
- if currentPlatform == OS.WINDOWS.value:
1166
- import ctypes
1167
- myappid = "SimBA development wheel"
1168
- ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
1169
- SplashMovie()
1170
- app = App()
1171
- app.root.mainloop()
1
+ __author__ = "Simon Nilsson; sronilsson@gmail.com"
2
+
3
+ from simba.utils.printing import SimbaTimer, stdout_success, stdout_warning
4
+
5
+ load_timer = SimbaTimer(start=True)
6
+ import os.path
7
+ import warnings
8
+
9
+ warnings.filterwarnings("ignore", category=FutureWarning)
10
+ warnings.filterwarnings("ignore", category=DeprecationWarning)
11
+ import atexit
12
+ import platform
13
+ import subprocess
14
+ import sys
15
+ import threading
16
+ import tkinter.ttk as ttk
17
+ import urllib.request
18
+ import webbrowser
19
+ from tkinter import *
20
+ from tkinter.filedialog import askdirectory
21
+ from tkinter.messagebox import askyesno
22
+ from typing import Union
23
+
24
+ import PIL.Image
25
+ from PIL import ImageTk
26
+
27
+ from simba.bounding_box_tools.boundary_menus import BoundaryMenus
28
+ from simba.labelling.labelling_advanced_interface import \
29
+ select_labelling_video_advanced
30
+ from simba.labelling.targeted_annotations_clips import \
31
+ select_labelling_video_targeted_clips
32
+ from simba.mixins.config_reader import ConfigReader
33
+ from simba.mixins.pop_up_mixin import PopUpMixin
34
+ from simba.model.grid_search_rf import GridSearchRandomForestClassifier
35
+ from simba.model.inference_validation import InferenceValidation
36
+ from simba.model.train_rf import TrainRandomForestClassifier
37
+ from simba.outlier_tools.outlier_corrector_location import \
38
+ OutlierCorrecterLocation
39
+ from simba.outlier_tools.outlier_corrector_movement import \
40
+ OutlierCorrecterMovement
41
+ from simba.outlier_tools.skip_outlier_correction import \
42
+ OutlierCorrectionSkipper
43
+ from simba.plotting.interactive_probability_grapher import \
44
+ InteractiveProbabilityGrapher
45
+ from simba.third_party_label_appenders.BENTO_appender import BentoAppender
46
+ from simba.third_party_label_appenders.BORIS_appender import BorisAppender
47
+ from simba.third_party_label_appenders.deepethogram_importer import \
48
+ DeepEthogramImporter
49
+ from simba.third_party_label_appenders.ethovision_import import \
50
+ ImportEthovision
51
+ from simba.third_party_label_appenders.observer_importer import \
52
+ NoldusObserverImporter
53
+ from simba.third_party_label_appenders.solomon_importer import SolomonImporter
54
+ from simba.ui.create_project_ui import ProjectCreatorPopUp
55
+ from simba.ui.import_pose_frame import ImportPoseFrame
56
+ from simba.ui.import_videos_frame import ImportVideosFrame
57
+ from simba.ui.machine_model_settings_ui import MachineModelSettingsPopUp
58
+ from simba.ui.pop_ups.about_simba_pop_up import AboutSimBAPopUp
59
+ from simba.ui.pop_ups.animal_directing_other_animals_pop_up import \
60
+ AnimalDirectingAnimalPopUp
61
+ from simba.ui.pop_ups.append_roi_features_animals_pop_up import \
62
+ AppendROIFeaturesByAnimalPopUp
63
+ from simba.ui.pop_ups.append_roi_features_bodypart_pop_up import \
64
+ AppendROIFeaturesByBodyPartPopUp
65
+ from simba.ui.pop_ups.archive_files_pop_up import ArchiveProcessedFilesPopUp
66
+ from simba.ui.pop_ups.batch_preprocess_pop_up import BatchPreProcessPopUp
67
+ from simba.ui.pop_ups.blob_visualizer_pop_up import BlobVisualizerPopUp
68
+ from simba.ui.pop_ups.boolean_conditional_slicer_pup_up import \
69
+ BooleanConditionalSlicerPopUp
70
+ from simba.ui.pop_ups.change_speed_popup import ChangeSpeedPopup
71
+ from simba.ui.pop_ups.check_videos_seekable_pop_up import \
72
+ CheckVideoSeekablePopUp
73
+ from simba.ui.pop_ups.clf_add_remove_print_pop_up import (
74
+ AddClfPopUp, PrintModelInfoPopUp, RemoveAClassifierPopUp)
75
+ from simba.ui.pop_ups.clf_annotation_counts_pop_up import \
76
+ ClfAnnotationCountPopUp
77
+ from simba.ui.pop_ups.clf_by_roi_pop_up import ClfByROIPopUp
78
+ from simba.ui.pop_ups.clf_by_timebins_pop_up import TimeBinsClfPopUp
79
+ from simba.ui.pop_ups.clf_descriptive_statistics_pop_up import \
80
+ ClfDescriptiveStatsPopUp
81
+ from simba.ui.pop_ups.clf_plot_pop_up import SklearnVisualizationPopUp
82
+ from simba.ui.pop_ups.clf_probability_plot_pop_up import \
83
+ VisualizeClassificationProbabilityPopUp
84
+ from simba.ui.pop_ups.clf_validation_plot_pop_up import \
85
+ ClassifierValidationPopUp
86
+ from simba.ui.pop_ups.coco_keypoints_to_yolo_popup import \
87
+ COCOKeypoints2YOLOkeypointsPopUp
88
+ from simba.ui.pop_ups.csv_2_parquet_pop_up import (Csv2ParquetPopUp,
89
+ Parquet2CsvPopUp)
90
+ from simba.ui.pop_ups.cue_light_main_popup import CueLightMainPopUp
91
+ from simba.ui.pop_ups.data_plot_pop_up import DataPlotterPopUp
92
+ from simba.ui.pop_ups.delete_all_rois_pop_up import delete_all_rois_pop_up
93
+ from simba.ui.pop_ups.directing_animal_to_bodypart_plot_pop_up import \
94
+ DirectingAnimalToBodyPartVisualizerPopUp
95
+ from simba.ui.pop_ups.directing_other_animals_plot_pop_up import \
96
+ DirectingOtherAnimalsVisualizerPopUp
97
+ from simba.ui.pop_ups.direction_animal_to_bodypart_settings_pop_up import \
98
+ DirectionAnimalToBodyPartSettingsPopUp
99
+ from simba.ui.pop_ups.distance_plot_pop_up import DistancePlotterPopUp
100
+ from simba.ui.pop_ups.dlc_h5_inference_to_yolo_popup import \
101
+ DLCH5Inference2YoloPopUp
102
+ from simba.ui.pop_ups.dlc_to_labelme_popup import DLC2LabelmePopUp
103
+ from simba.ui.pop_ups.dlc_to_yolo_keypoints_popup import DLCYoloKeypointsPopUp
104
+ from simba.ui.pop_ups.egocentric_alignment_pop_up import EgocentricAlignPopUp
105
+ from simba.ui.pop_ups.extract_annotation_frames_pop_up import \
106
+ ExtractAnnotationFramesPopUp
107
+ from simba.ui.pop_ups.fsttc_pop_up import FSTTCPopUp
108
+ from simba.ui.pop_ups.gantt_pop_up import GanttPlotPopUp
109
+ from simba.ui.pop_ups.heatmap_clf_pop_up import HeatmapClfPopUp
110
+ from simba.ui.pop_ups.heatmap_location_pop_up import HeatmapLocationPopup
111
+ from simba.ui.pop_ups.initialize_blob_tracking_pop_up import \
112
+ InitializeBlobTrackerPopUp
113
+ from simba.ui.pop_ups.interpolate_pop_up import InterpolatePopUp
114
+ from simba.ui.pop_ups.kleinberg_pop_up import KleinbergPopUp
115
+ from simba.ui.pop_ups.labelme_bbox_to_yolo_bbox_popup import \
116
+ LabelmeBbox2YoloBboxPopUp
117
+ from simba.ui.pop_ups.labelme_to_df_popup import Labelme2DataFramePopUp
118
+ from simba.ui.pop_ups.labelme_to_imgs_popup import Labelme2ImgsPopUp
119
+ from simba.ui.pop_ups.make_path_plot_pop_up import MakePathPlotPopUp
120
+ from simba.ui.pop_ups.merge_coco_keypoint_files_pop_up import \
121
+ MergeCOCOKeypointFilesPopUp
122
+ from simba.ui.pop_ups.movement_analysis_pop_up import \
123
+ MovementAnalysisPopUp # ## LAZY
124
+ from simba.ui.pop_ups.movement_analysis_time_bins_pop_up import \
125
+ MovementAnalysisTimeBinsPopUp
126
+ from simba.ui.pop_ups.multiple_videos_to_frames_popup import \
127
+ MultipleVideos2FramesPopUp
128
+ from simba.ui.pop_ups.mutual_exclusivity_pop_up import MutualExclusivityPupUp
129
+ from simba.ui.pop_ups.outlier_settings_pop_up import OutlierSettingsPopUp
130
+ from simba.ui.pop_ups.path_plot_pop_up import PathPlotPopUp
131
+ from simba.ui.pop_ups.pose_bp_drop_pop_up import DropTrackingDataPopUp
132
+ from simba.ui.pop_ups.pose_reorganizer_pop_up import PoseReorganizerPopUp
133
+ from simba.ui.pop_ups.print_video_meta_popup import PrintVideoMetaDataPopUp
134
+ from simba.ui.pop_ups.pup_retrieval_pop_up import PupRetrievalPopUp
135
+ from simba.ui.pop_ups.quick_path_plot_pop_up import QuickLineplotPopup
136
+ from simba.ui.pop_ups.remove_roi_features_pop_up import RemoveROIFeaturesPopUp
137
+ from simba.ui.pop_ups.roi_aggregate_stats_popup import \
138
+ ROIAggregateDataAnalyzerPopUp
139
+ from simba.ui.pop_ups.roi_analysis_time_bins_pop_up import \
140
+ ROIAnalysisTimeBinsPopUp
141
+ from simba.ui.pop_ups.roi_features_plot_pop_up import VisualizeROIFeaturesPopUp
142
+ from simba.ui.pop_ups.roi_tracking_plot_pop_up import VisualizeROITrackingPopUp
143
+ from simba.ui.pop_ups.roi_video_table_pop_up import ROIVideoTable
144
+ from simba.ui.pop_ups.run_machine_models_popup import RunMachineModelsPopUp
145
+ from simba.ui.pop_ups.select_video_for_labelling_popup import \
146
+ SelectLabellingVideoPupUp
147
+ from simba.ui.pop_ups.select_video_for_pseudo_labelling_popup import \
148
+ SelectPseudoLabellingVideoPupUp
149
+ from simba.ui.pop_ups.severity_analysis_pop_up import AnalyzeSeverityPopUp
150
+ from simba.ui.pop_ups.simba_rois_to_yolo_pop_up import SimBAROIs2YOLOPopUp
151
+ from simba.ui.pop_ups.simba_to_yolo_keypoints_popup import \
152
+ SimBA2YoloKeypointsPopUp
153
+ from simba.ui.pop_ups.single_video_to_frames_popup import \
154
+ SingleVideo2FramesPopUp
155
+ from simba.ui.pop_ups.sleap_annotations_to_yolo_popup import \
156
+ SLEAPAnnotations2YoloPopUp
157
+ from simba.ui.pop_ups.sleap_csv_predictions_to_yolo_popup import \
158
+ SLEAPcsvInference2Yolo
159
+ from simba.ui.pop_ups.sleap_h5_inference_to_yolo_popup import \
160
+ SLEAPH5Inference2YoloPopUp
161
+ from simba.ui.pop_ups.smoothing_popup import SmoothingPopUp
162
+ from simba.ui.pop_ups.splash_popup import SplashMovie
163
+ from simba.ui.pop_ups.spontaneous_alternation_pop_up import \
164
+ SpontaneousAlternationPopUp # ## LAZY
165
+ from simba.ui.pop_ups.subset_feature_extractor_pop_up import \
166
+ FeatureSubsetExtractorPopUp
167
+ from simba.ui.pop_ups.third_party_annotator_appender_pop_up import \
168
+ ThirdPartyAnnotatorAppenderPopUp
169
+ from simba.ui.pop_ups.validation_plot_pop_up import ValidationVideoPopUp
170
+ from simba.ui.pop_ups.video_processing_pop_up import (
171
+ BackgroundRemoverDirectoryPopUp, BackgroundRemoverSingleVideoPopUp,
172
+ BoxBlurPopUp, BrightnessContrastPopUp, CalculatePixelsPerMMInVideoPopUp,
173
+ ChangeFpsMultipleVideosPopUp, ChangeFpsSingleVideoPopUp, CLAHEPopUp,
174
+ ClipSingleVideoByFrameNumbers, ClipVideoPopUp, ConcatenatingVideosPopUp,
175
+ ConcatenatorPopUp, Convert2AVIPopUp, Convert2BlackWhitePopUp,
176
+ Convert2bmpPopUp, Convert2jpegPopUp, Convert2MOVPopUp, Convert2MP4PopUp,
177
+ Convert2PNGPopUp, Convert2TIFFPopUp, Convert2WEBMPopUp, Convert2WEBPPopUp,
178
+ ConvertROIDefinitionsPopUp, CreateAverageFramePopUp, CreateGIFPopUP,
179
+ CropVideoCirclesPopUp, CropVideoPolygonsPopUp, CropVideoPopUp,
180
+ CrossfadeVideosPopUp, DownsampleMultipleVideosPopUp,
181
+ DownsampleSingleVideoPopUp, ExtractSEQFramesPopUp,
182
+ ExtractSpecificFramesPopUp, FlipVideosPopUp, GreyscaleSingleVideoPopUp,
183
+ ImportFrameDirectoryPopUp, InitiateClipMultipleVideosByFrameNumbersPopUp,
184
+ InitiateClipMultipleVideosByTimestampsPopUp, InteractiveClahePopUp,
185
+ ManualTemporalJoinPopUp, MergeFrames2VideoPopUp, MultiCropPopUp,
186
+ MultiShortenPopUp, ReverseVideoPopUp, RotateVideoSetDegreesPopUp,
187
+ SuperImposeFrameCountPopUp, SuperimposeProgressBarPopUp,
188
+ SuperimposeTextPopUp, SuperimposeTimerPopUp, SuperimposeVideoNamesPopUp,
189
+ SuperimposeVideoPopUp, SuperimposeWatermarkPopUp, UpsampleVideosPopUp,
190
+ VideoRotatorPopUp, VideoTemporalJoinPopUp)
191
+ from simba.ui.pop_ups.visualize_pose_in_dir_pop_up import \
192
+ VisualizePoseInFolderPopUp
193
+ from simba.ui.pop_ups.yolo_inference_popup import YOLOPoseInferencePopUP
194
+ from simba.ui.pop_ups.yolo_plot_results import YoloPoseVisualizerPopUp
195
+ from simba.ui.pop_ups.yolo_pose_train_popup import YOLOPoseTrainPopUP
196
+ from simba.ui.tkinter_functions import (CreateLabelFrameWithIcon, Entry_Box,
197
+ FileSelect, SimbaButton, SimbaCheckbox,
198
+ SimBADropDown, SimBALabel,
199
+ hxtScrollbar)
200
+ from simba.ui.video_info_ui import VideoInfoTable
201
+ from simba.utils.checks import (check_ffmpeg_available,
202
+ check_file_exist_and_readable, check_int)
203
+ from simba.utils.custom_feature_extractor import CustomFeatureExtractor
204
+ from simba.utils.enums import (ENV_VARS, OS, ConfigKey, Defaults, Dtypes,
205
+ Formats, Keys, Links, PackageNames, Paths,
206
+ TagNames)
207
+ from simba.utils.errors import InvalidInputError
208
+ from simba.utils.lookups import (check_for_updates,
209
+ get_bp_config_code_class_pairs,
210
+ get_current_time, get_emojis, get_icons_paths,
211
+ load_simba_fonts)
212
+ from simba.utils.read_write import (fetch_pip_data, find_core_cnt,
213
+ get_pkg_version, get_recent_projects_paths,
214
+ read_config_entry, read_config_file,
215
+ read_sys_env, remove_files,
216
+ write_to_recent_project_paths)
217
+ from simba.utils.warnings import (FFMpegNotFoundWarning, PythonVersionWarning,
218
+ VersionWarning)
219
+ from simba.video_processors.video_processing import \
220
+ extract_frames_from_all_videos_in_directory
221
+
222
+ sys.setrecursionlimit(10**6)
223
+ currentPlatform = platform.system()
224
+ ENV = read_sys_env()
225
+ load_timer.stop_timer()
226
+
227
+ try:
228
+ import multiprocessing
229
+ is_worker_process = multiprocessing.current_process().name != 'MainProcess'
230
+ except (ImportError, AttributeError):
231
+ is_worker_process = False
232
+ if not is_worker_process:
233
+ print(f'SimBA environment variables: {ENV}. Load time: {load_timer.elapsed_time_str}s')
234
+
235
+ class LoadProjectPopUp(object):
236
+ def __init__(self):
237
+ self.main_frm = Toplevel()
238
+ self.main_frm.minsize(300, 200)
239
+ self.main_frm.wm_title("Load SimBA project (project_config.ini file)")
240
+ self.btn_icons = get_icons_paths()
241
+ for k in self.btn_icons.keys(): self.btn_icons[k]["img"] = ImageTk.PhotoImage(image=PIL.Image.open(os.path.join(os.path.dirname(__file__), self.btn_icons[k]["icon_path"])))
242
+ self.main_frm.iconphoto(False, self.btn_icons['browse']["img"])
243
+ self.load_project_frm = CreateLabelFrameWithIcon(parent=self.main_frm, header="LOAD SIMBA PROJECT_CONFIG.INI", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.LOAD_PROJECT.value)
244
+ self.selected_file = FileSelect(self.load_project_frm, "SIMBA CONFIG FILE: ", title="Select project_config.ini file", file_types=[("SimBA Project .ini", "*.ini")], lblwidth=30, lbl_icon='file_type')
245
+ load_project_btn = SimbaButton(parent=self.load_project_frm, txt="LOAD PROJECT PATH", txt_clr='blue', img='rocket', font=Formats.FONT_REGULAR.value, cmd=self.launch_project, cmd_kwargs={'project_path': lambda: self.selected_file.file_path})
246
+ #load_project_btn = SimbaButton(parent=self.load_project_frm, txt="LOAD PROJECT PATH", txt_clr='blue', img='rocket', font=Formats.FONT_REGULAR.value, cmd=self.launch_project, cmd_kwargs={'project_path': self.selected_file.file_path})
247
+ self.load_project_frm.grid(row=0, sticky=NW, pady=(0, 10))
248
+ self.selected_file.grid(row=0, sticky=NW)
249
+ load_project_btn.grid(row=1, pady=(3, 0), sticky=NW)
250
+ recent_project_paths = get_recent_projects_paths()
251
+ if len(recent_project_paths) > 0:
252
+ max_len = max(len(s) for s in recent_project_paths)
253
+ self.load_recent_frm = CreateLabelFrameWithIcon(parent=self.main_frm, header="LOAD RECENT PROJECT", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.LOAD_PROJECT.value)
254
+ self.recent_project_dropdown = SimBADropDown(parent=self.load_recent_frm, dropdown_options=recent_project_paths, label='RECENT CONFIG FILE PATH:', label_width=30, value=recent_project_paths[0], dropdown_width=max_len)
255
+ self.load_recent_project_btn = SimbaButton(parent=self.load_recent_frm, txt="LOAD RECENT PROJECT", txt_clr='darkgreen', img='rocket', font=Formats.FONT_REGULAR.value, cmd=self.launch_project, cmd_kwargs={'project_path': lambda: self.recent_project_dropdown.get_value()})
256
+ self.load_recent_frm.grid(row=1, sticky=NW)
257
+ self.recent_project_dropdown.grid(row=0, sticky=NW)
258
+ self.load_recent_project_btn.grid(row=1, pady=(5, 0), sticky=NW)
259
+
260
+ def launch_project(self, project_path: str):
261
+ check_file_exist_and_readable(file_path=project_path)
262
+ _ = SimbaProjectPopUp(config_path=project_path)
263
+ self.load_project_frm.destroy()
264
+ self.main_frm.destroy()
265
+
266
+
267
+ def wait_for_internet_connection(url):
268
+ while True:
269
+ try:
270
+ response = urllib.request.urlopen(url, timeout=1)
271
+ return
272
+ except:
273
+ pass
274
+
275
+
276
+ class SimbaProjectPopUp(ConfigReader, PopUpMixin):
277
+ """
278
+ Main entry to the SimBA loaded project pop-up.
279
+ """
280
+
281
+ def __init__(self, config_path: Union[str, os.PathLike]):
282
+
283
+ ConfigReader.__init__(self, config_path=config_path, read_video_info=False)
284
+ stdout_success(f"Loaded project {config_path}", source=self.__class__.__name__)
285
+ simongui = Toplevel()
286
+ simongui.attributes("-topmost", True)
287
+ simongui.after(150, lambda: simongui.attributes("-topmost", False))
288
+ simongui.minsize(1300, 800)
289
+ try:
290
+ config = read_config_file(config_path=config_path)
291
+ project_name = read_config_entry(config=config, section=ConfigKey.GENERAL_SETTINGS.value, option=ConfigKey.PROJECT_NAME.value, default_value="LOAD PROJECT", data_type=Dtypes.STR.value)
292
+ project_name = f'{project_name} ({config_path})'
293
+ except:
294
+ project_name = "LOAD PROJECT"
295
+ simongui.wm_title(project_name)
296
+ simongui.columnconfigure(0, weight=1)
297
+ simongui.rowconfigure(0, weight=1)
298
+ self.core_cnt = find_core_cnt()[0]
299
+ self.btn_icons = get_icons_paths()
300
+
301
+ for k in self.btn_icons.keys():
302
+ self.btn_icons[k]["img"] = ImageTk.PhotoImage(image=PIL.Image.open(os.path.join(os.path.dirname(__file__), self.btn_icons[k]["icon_path"])))
303
+
304
+ simongui.iconphoto(False, self.btn_icons['SimBA_logo_3_small']["img"])
305
+ tab_style = ttk.Style()
306
+ tab_style.configure('Custom.TNotebook', background='#f0f0f0', borderwidth=0)
307
+ tab_style.configure('Custom.TNotebook.Tab', font=Formats.FONT_REGULAR.value, padding=[15, 8], borderwidth=1, relief='flat', background='#f0f0f0')
308
+ tab_style.map('Custom.TNotebook.Tab',
309
+ background=[('selected', '#ffffff'), ('!selected', '#f0f0f0')],
310
+ foreground=[('selected', 'navy'), ('!selected', '#333333')],
311
+ font=[('selected', Formats.FONT_REGULAR_BOLD.value), ('!selected', Formats.FONT_REGULAR.value)],
312
+ bordercolor=[('selected', '#0066cc'), ('!selected', '#e0e0e0')],
313
+ lightcolor=[('selected', '#ffffff'), ('!selected', '#f5f5f5')],
314
+ darkcolor=[('selected', '#e0e0e0'), ('!selected', '#e0e0e0')])
315
+
316
+ scrollable_container = hxtScrollbar(simongui)
317
+ tab_parent = ttk.Notebook(scrollable_container, style='Custom.TNotebook')
318
+ tab2 = ttk.Frame(tab_parent)
319
+ tab3 = ttk.Frame(tab_parent)
320
+ tab4 = ttk.Frame(tab_parent)
321
+ tab5 = ttk.Frame(tab_parent)
322
+ tab6 = ttk.Frame(tab_parent)
323
+ tab7 = ttk.Frame(tab_parent)
324
+ tab8 = ttk.Frame(tab_parent)
325
+ tab9 = ttk.Frame(tab_parent)
326
+ tab10 = ttk.Frame(tab_parent)
327
+ tab11 = ttk.Frame(tab_parent)
328
+
329
+ tab_parent.add(tab2, text="Further imports", compound="left", image=self.btn_icons["pose"]["img"])
330
+ tab_parent.add(tab3, text="Video parameters", compound="left", image=self.btn_icons["calipher"]["img"])
331
+ tab_parent.add(tab4, text="Outlier correction", compound="left", image=self.btn_icons["outlier"]["img"])
332
+ tab_parent.add(tab6, text="ROI", compound="left", image=self.btn_icons["roi"]["img"])
333
+ tab_parent.add(tab5, text="Extract features", compound="left", image=self.btn_icons["features"]["img"])
334
+ tab_parent.add(tab7, text="Label behavior", compound="left", image=self.btn_icons["label"]["img"])
335
+ tab_parent.add(tab8, text="Train machine model", compound="left", image=self.btn_icons["clf"]["img"])
336
+ tab_parent.add(tab9, text="Run machine model", compound="left", image=self.btn_icons["clf_2"]["img"])
337
+ tab_parent.add(tab10, text="Visualizations", compound="left", image=self.btn_icons["visualize"]["img"])
338
+ tab_parent.add(tab11, text="Add-ons", compound="left", image=self.btn_icons["add_on"]["img"])
339
+
340
+ tab_parent.grid(row=0, sticky='ew')
341
+ tab_parent.enable_traversal()
342
+
343
+ import_frm = LabelFrame(tab2)
344
+ import_frm.grid(row=0, column=0, sticky=NW)
345
+
346
+ further_methods_frm = CreateLabelFrameWithIcon(parent=import_frm, header="FURTHER METHODS", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.ADDITIONAL_IMPORTS.value, bg=Formats.LABELFRAME_GREY.value, padx=5, pady=5)
347
+ extract_frm_btn = SimbaButton(parent=further_methods_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="EXTRACT FRAMES FOR ALL VIDEOS IN SIMBA PROJECT", txt_clr='blue', compound='right', img='image', font=Formats.FONT_REGULAR.value, cmd=extract_frames_from_all_videos_in_directory, cmd_kwargs={'config_path': lambda:self.config_path, 'directory': lambda:self.video_dir})
348
+ import_frm_dir_btn = SimbaButton(parent=further_methods_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="IMPORT FRAMES DIRECTORY TO SIMBA PROJECT", txt_clr='blue', compound='right', img='import', font=Formats.FONT_REGULAR.value, cmd=ImportFrameDirectoryPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
349
+ add_clf_btn = SimbaButton(parent=further_methods_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="ADD CLASSIFIER TO SIMBA PROJECT", txt_clr='blue', compound='right', img='plus', font=Formats.FONT_REGULAR.value, cmd=AddClfPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
350
+ remove_clf_btn = SimbaButton(parent=further_methods_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="REMOVE CLASSIFIER FROM SIMBA PROJECT", txt_clr='blue', compound='right', img='trash', font=Formats.FONT_REGULAR.value, cmd=RemoveAClassifierPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
351
+ archive_files_btn = SimbaButton(parent=further_methods_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="ARCHIVE PROCESSED FILES IN SIMBA PROJECT", txt_clr='blue', compound='right', img='archive', font=Formats.FONT_REGULAR.value, cmd=ArchiveProcessedFilesPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
352
+ reverse_btn = SimbaButton(parent=further_methods_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="REVERSE TRACKING IDENTITIES IN SIMBA PROJECT", txt_clr='blue', compound='right', img='reverse_blue', font=Formats.FONT_REGULAR.value, cmd=None)
353
+ interpolate_btn = SimbaButton(parent=further_methods_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="INTERPOLATE POSE IN SIMBA PROJECT", txt_clr='blue', compound='right', img='line_chart_blue', font=Formats.FONT_REGULAR.value, cmd=InterpolatePopUp, cmd_kwargs={'config_path': lambda:self.config_path})
354
+ smooth_btn = SimbaButton(parent=further_methods_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="SMOOTH POSE IN SIMBA PROJECT", txt_clr='blue', compound='right', img='wand_blue', font=Formats.FONT_REGULAR.value, cmd=SmoothingPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
355
+ egocentric_align_btn = SimbaButton(parent=further_methods_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="EGOCENTRICALLY ALIGN POSE AND VIDEO", txt_clr='blue', compound='right', img='mouse_small', font=Formats.FONT_REGULAR.value, cmd=EgocentricAlignPopUp, cmd_kwargs={'config_path': lambda: self.config_path})
356
+
357
+ label_setscale = CreateLabelFrameWithIcon(parent=tab3, header="VIDEO PARAMETERS (FPS, RESOLUTION, PPX/MM ....)", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.VIDEO_PARAMETERS.value, padx=10, pady=10, relief='solid')
358
+ self.distance_in_mm_eb = Entry_Box(label_setscale, "KNOWN DISTANCE (MILLIMETERS): ", labelwidth=35, validation="numeric", entry_box_width=35)
359
+ button_setdistanceinmm = SimbaButton(parent=label_setscale, txt="AUTO-POPULATE", txt_clr='blue', font=Formats.FONT_REGULAR.value, cmd=self.set_distance_mm)
360
+
361
+ button_setscale = SimbaButton(parent=label_setscale, txt="CONFIGURE VIDEO PARAMETERS", txt_clr='blue', font=Formats.FONT_REGULAR.value, cmd=self.create_video_info_table, img='calipher')
362
+ self.new_ROI_frm = CreateLabelFrameWithIcon(parent=tab6, header="SIMBA ROI INTERFACE", icon_name='shapes_small', icon_link=Links.ROI.value, bg='#DCDCDC', padx=5, pady=5)
363
+ self.start_new_ROI = SimbaButton(parent=self.new_ROI_frm, width=Formats.BUTTON_WIDTH_L.value, txt="DEFINE ROIs", txt_clr='green', font=Formats.FONT_REGULAR.value, img='roi', cmd=ROIVideoTable, cmd_kwargs={'config_path': lambda:self.config_path})
364
+
365
+ self.delete_all_ROIs = SimbaButton(parent=self.new_ROI_frm, width=Formats.BUTTON_WIDTH_L.value, txt="DELETE ALL ROI DEFINITIONS", txt_clr='red', font=Formats.FONT_REGULAR.value, img='trash', cmd=delete_all_rois_pop_up, cmd_kwargs={'config_path': lambda:self.config_path})
366
+ self.new_ROI_frm.grid(row=0, sticky=NW, padx=10, pady=10)
367
+ self.start_new_ROI.grid(row=0, sticky=NW)
368
+ self.delete_all_ROIs.grid(row=1, column=0, sticky=NW)
369
+
370
+ self.roi_draw = CreateLabelFrameWithIcon(parent=tab6, header="ANALYZE ROI DATA", icon_name='magnifying', icon_link=Links.ROI.value, bg='#DCDCDC', padx=5, pady=5)
371
+ analyze_roi_btn = SimbaButton(parent=self.roi_draw, width=Formats.BUTTON_WIDTH_L.value, txt="ANALYZE ROI DATA: AGGREGATES", txt_clr='green', img='shapes_small', font=Formats.FONT_REGULAR.value, cmd=ROIAggregateDataAnalyzerPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
372
+
373
+ analyze_roi_time_bins_btn = SimbaButton(parent=self.roi_draw, width=Formats.BUTTON_WIDTH_L.value, txt="ANALYZE ROI DATA: TIME-BINS", txt_clr='blue', img='clock', font=Formats.FONT_REGULAR.value, cmd=ROIAnalysisTimeBinsPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
374
+ self.roi_draw.grid(row=0, column=1, sticky=N, padx=10, pady=10)
375
+ analyze_roi_btn.grid(row=0, sticky="NW")
376
+ analyze_roi_time_bins_btn.grid(row=1, sticky="NW")
377
+
378
+ self.roi_draw1 = CreateLabelFrameWithIcon(parent=tab6, header="VISUALIZE ROI DATA", icon_name='eye', icon_link=Links.ROI.value, bg='#DCDCDC', padx=5, pady=5)
379
+ visualizeROI = SimbaButton(parent=self.roi_draw1, width=Formats.BUTTON_WIDTH_L.value, txt="VISUALIZE ROI TRACKING", txt_clr='green', img='visualize_green', font=Formats.FONT_REGULAR.value, cmd=VisualizeROITrackingPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
380
+ visualizeROIfeature = SimbaButton(parent=self.roi_draw1, width=Formats.BUTTON_WIDTH_L.value, txt="VISUALIZE ROI FEATURES", txt_clr='blue', img='visualize_blue', font=Formats.FONT_REGULAR.value, cmd=VisualizeROIFeaturesPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
381
+
382
+ ##organize
383
+ self.roi_draw1.grid(row=0, column=2, sticky=N, padx=10, pady=10)
384
+ visualizeROI.grid(row=0, sticky="NW")
385
+ visualizeROIfeature.grid(row=1, sticky="NW")
386
+
387
+ processmovementdupLabel = CreateLabelFrameWithIcon(parent=tab6, header="OTHER ANALYSES / VISUALIZATIONS", icon_name='list', icon_link=Links.ROI.value, bg='#DCDCDC', padx=5, pady=5)
388
+ analyze_distances_velocity_btn = SimbaButton(parent=processmovementdupLabel, width=Formats.BUTTON_WIDTH_XL.value, txt="ANALYZE DISTANCES / VELOCITY: AGGREGATES", img='metrics_green', txt_clr='green', font=Formats.FONT_REGULAR.value, cmd=MovementAnalysisPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
389
+ analyze_distances_velocity_timebins_btn = SimbaButton(parent=processmovementdupLabel, width=Formats.BUTTON_WIDTH_XL.value, txt="ANALYZE DISTANCES / VELOCITY: TIME-BINS", img='metrics_blue', txt_clr='blue', font=Formats.FONT_REGULAR.value, cmd=MovementAnalysisTimeBinsPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
390
+ heatmaps_location_button = SimbaButton(parent=processmovementdupLabel, width=Formats.BUTTON_WIDTH_XL.value, txt="CREATE LOCATION HEATMAPS", txt_clr='red', img='heatmap', font=Formats.FONT_REGULAR.value, cmd=HeatmapLocationPopup, cmd_kwargs={'config_path': lambda:self.config_path})
391
+ button_lineplot = SimbaButton(parent=processmovementdupLabel, width=Formats.BUTTON_WIDTH_XL.value, txt="CREATE PATH PLOTS", txt_clr='orange', img='path', font=Formats.FONT_REGULAR.value, cmd=QuickLineplotPopup, cmd_kwargs={'config_path': lambda:self.config_path})
392
+
393
+ button_analyzeDirection = SimbaButton(parent=processmovementdupLabel, width=Formats.BUTTON_WIDTH_XL.value, txt="ANALYZE DIRECTIONALITY BETWEEN ANIMALS", img='direction', txt_clr='deeppink', font=Formats.FONT_REGULAR.value, cmd=AnimalDirectingAnimalPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
394
+ button_visualizeDirection = SimbaButton(parent=processmovementdupLabel, width=Formats.BUTTON_WIDTH_XL.value, txt="VISUALIZE DIRECTIONALITY BETWEEN ANIMALS", img='direction', txt_clr='brown', font=Formats.FONT_REGULAR.value, cmd=DirectingOtherAnimalsVisualizerPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
395
+ button_analyzeDirection_bp = SimbaButton(parent=processmovementdupLabel, width=Formats.BUTTON_WIDTH_XL.value, txt="ANALYZE DIRECTIONALITY BETWEEN BODY PARTS", img='direction', txt_clr='purple', font=Formats.FONT_REGULAR.value, cmd=DirectionAnimalToBodyPartSettingsPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
396
+ button_visualizeDirection_bp = SimbaButton(parent=processmovementdupLabel, width=Formats.BUTTON_WIDTH_XL.value, txt="VISUALIZE DIRECTIONALITY BETWEEN BODY PARTS", img='direction', txt_clr='black', font=Formats.FONT_REGULAR.value, cmd=DirectingAnimalToBodyPartVisualizerPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
397
+
398
+ btn_agg_boolean_conditional_statistics = SimbaButton(parent=processmovementdupLabel, width=Formats.BUTTON_WIDTH_XL.value, txt="AGGREGATE BOOLEAN CONDITIONAL STATISTICS", img='details', txt_clr='grey', font=Formats.FONT_REGULAR.value, cmd=BooleanConditionalSlicerPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
399
+ spontaneous_alternation_pop_up_btn = SimbaButton(parent=processmovementdupLabel, width=Formats.BUTTON_WIDTH_XL.value, txt="SPONTANEOUS ALTERNATION", img='t', txt_clr='navy', font=Formats.FONT_REGULAR.value, cmd=SpontaneousAlternationPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
400
+
401
+ processmovementdupLabel.grid(row=0, column=3, sticky=NW, padx=10, pady=10)
402
+ analyze_distances_velocity_btn.grid(row=0, sticky=NW)
403
+ heatmaps_location_button.grid(row=1, sticky=NW)
404
+ analyze_distances_velocity_timebins_btn.grid(row=2, sticky=NW)
405
+ button_lineplot.grid(row=3, sticky=NW)
406
+ button_analyzeDirection.grid(row=4, sticky=NW)
407
+ button_visualizeDirection.grid(row=5, sticky=NW)
408
+ button_analyzeDirection_bp.grid(row=6, sticky=NW)
409
+ button_visualizeDirection_bp.grid(row=7, sticky=NW)
410
+ btn_agg_boolean_conditional_statistics.grid(row=8, sticky=NW)
411
+ spontaneous_alternation_pop_up_btn.grid(row=9, sticky=NW)
412
+
413
+ label_outliercorrection = CreateLabelFrameWithIcon(parent=tab4, header="OUTLIER CORRECTION", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.OUTLIERS_DOC.value, bg=Formats.LABELFRAME_GREY.value, padx=5, pady=5)
414
+ button_settings_outlier = SimbaButton(parent=label_outliercorrection, width=Formats.BUTTON_WIDTH_L.value, txt="SETTINGS", txt_clr='blue', img='settings', font=Formats.FONT_REGULAR.value, cmd=OutlierSettingsPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
415
+
416
+ button_outliercorrection = SimbaButton(parent=label_outliercorrection, width=Formats.BUTTON_WIDTH_L.value, txt="RUN OUTLIER CORRECTION", txt_clr='green', img='rocket', font=Formats.FONT_REGULAR.value, cmd=self.correct_outlier, thread=False)
417
+ button_skipOC = SimbaButton(parent=label_outliercorrection, width=Formats.BUTTON_WIDTH_L.value, txt="SKIP OUTLIER CORRECTION (CAUTION)", txt_clr='red', img='skip_2', font=Formats.FONT_REGULAR.value, cmd=self.initiate_skip_outlier_correction, thread=False)
418
+
419
+ def activate():
420
+ if self.user_defined_var.get(): self.scriptfile.set_state(setstatus=NORMAL)
421
+ else: self.scriptfile.set_state(setstatus=DISABLED)
422
+
423
+ extract_features_frm = CreateLabelFrameWithIcon(parent=tab5, header="EXTRACT FEATURES", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.EXTRACT_FEATURES.value, relief='solid')
424
+ userscript, self.user_defined_var = SimbaCheckbox(parent=extract_features_frm, txt="APPLY USER DEFINED FEATURE EXTRACTION SCRIPT", font=Formats.FONT_REGULAR.value, val=False, state=NORMAL, cmd= activate)
425
+ self.scriptfile = FileSelect(extract_features_frm, "SCRIPT PATH (.PY):", file_types=[("Python .py file", "*.py")], lblwidth=25, status=DISABLED, lbl_icon='python')
426
+ button_extractfeatures = SimbaButton(parent=extract_features_frm, txt="EXTRACT FEATURES", width=Formats.BUTTON_WIDTH_XL.value, txt_clr='blue', img='rocket', font=Formats.FONT_REGULAR.value, cmd=self.run_feature_extraction, thread=False)
427
+
428
+ extract_features_frm.grid(row=0, column=0, sticky=NSEW, padx=10, pady=10)
429
+ userscript.grid(row=0, column=0, sticky=NW)
430
+ self.scriptfile.grid(row=1, column=0, sticky=NW)
431
+ button_extractfeatures.grid(row=2, column=0, sticky=NW)
432
+
433
+ roi_feature_frm = CreateLabelFrameWithIcon(parent=tab5, header="APPEND ROI FEATURES", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.APPEND_ROI_FEATURES.value, bg=Formats.LABELFRAME_GREY.value, padx=5, pady=5)
434
+
435
+ append_roi_features_by_animal = SimbaButton(parent=roi_feature_frm, width=Formats.BUTTON_WIDTH_XXL.value, txt="APPEND ROI DATA TO FEATURES: BY ANIMAL (CAUTION)", txt_clr='red', img='join_red', font=Formats.FONT_REGULAR.value, cmd=AppendROIFeaturesByAnimalPopUp, cmd_kwargs={'config_path': lambda:self.config_path}, thread=False)
436
+ append_roi_features_by_body_part = SimbaButton(parent=roi_feature_frm, width=Formats.BUTTON_WIDTH_XXL.value, txt="APPEND ROI DATA TO FEATURES: BY BODY-PARTS (CAUTION)", img='join_yellow', txt_clr='orange', font=Formats.FONT_REGULAR.value, cmd=AppendROIFeaturesByBodyPartPopUp, cmd_kwargs={'config_path': lambda:self.config_path}, thread=False)
437
+ remove_roi_features_from_feature_set = SimbaButton(parent=roi_feature_frm, width=Formats.BUTTON_WIDTH_XXL.value, txt="REMOVE ROI FEATURES FROM FEATURE SET", txt_clr='darkred', img='trash', font=Formats.FONT_REGULAR.value, cmd=RemoveROIFeaturesPopUp, cmd_kwargs={'config_path': lambda:self.config_path, 'dataset': lambda:'features_extracted'}, thread=False)
438
+
439
+
440
+ feature_tools_frm = LabelFrame(tab5, text="FEATURE TOOLS", pady=5, font=Formats.FONT_HEADER.value, bg=Formats.LABELFRAME_GREY.value, padx=5)
441
+ compute_feature_subset_btn = SimbaButton(parent=feature_tools_frm, width=Formats.BUTTON_WIDTH_XXL.value, txt="CALCULATE FEATURE SUBSETS", txt_clr='blue', img='subset_blue', font=Formats.FONT_REGULAR.value, cmd=FeatureSubsetExtractorPopUp, cmd_kwargs={'config_path': lambda: self.config_path}, thread=False)
442
+
443
+ label_behavior_frm = CreateLabelFrameWithIcon(parent=tab7, header="LABEL BEHAVIOR", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.LABEL_BEHAVIOR.value, bg=Formats.LABELFRAME_GREY.value, padx=5, pady=5)
444
+ select_video_btn_new = SimbaButton(parent=label_behavior_frm, width=Formats.BUTTON_WIDTH_XXL.value, txt="Select video (create NEW video annotation)", img='label_blue', txt_clr='navy', cmd=SelectLabellingVideoPupUp, cmd_kwargs={'config_path': lambda :self.config_path, 'continuing': lambda: False}, thread=False)
445
+ select_video_btn_continue = SimbaButton(parent=label_behavior_frm, width=Formats.BUTTON_WIDTH_XXL.value, txt="Select video (CONTINUE existing video annotation)", img='label_yellow', txt_clr='darkgoldenrod', cmd=SelectLabellingVideoPupUp, cmd_kwargs={'config_path': lambda: self.config_path,'continuing': lambda: True}, thread=False)
446
+
447
+ label_thirdpartyann = CreateLabelFrameWithIcon(parent=tab7, header="IMPORT THIRD-PARTY BEHAVIOR ANNOTATIONS", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.THIRD_PARTY_ANNOTATION.value, bg=Formats.LABELFRAME_GREY.value, padx=5, pady=5)
448
+ button_importmars = SimbaButton(parent=label_thirdpartyann, width=Formats.BUTTON_WIDTH_XS.value, txt="Import MARS Annotation (select folder with .annot files)", txt_clr="blue", cmd=self.importMARS, thread=False, font=Formats.FONT_REGULAR.value)
449
+ button_importboris = SimbaButton(parent=label_thirdpartyann, width=Formats.BUTTON_WIDTH_XS.value, txt="Import BORIS Annotation (select folder with .csv files)", txt_clr="green", cmd=self.importBoris, thread=False, font=Formats.FONT_REGULAR.value)
450
+ button_importsolomon = SimbaButton(parent=label_thirdpartyann, width=Formats.BUTTON_WIDTH_XS.value, txt="Import SOLOMON Annotation (select folder with .csv files", txt_clr="purple", cmd=self.importSolomon, thread=False, font=Formats.FONT_REGULAR.value)
451
+
452
+ button_importethovision = SimbaButton(parent=label_thirdpartyann, width=Formats.BUTTON_WIDTH_XS.value, txt="Import ETHOVISION Annotation (select folder with .xls/xlsx files)", txt_clr="blue", cmd=self.import_ethovision, thread=False, font=Formats.FONT_REGULAR.value)
453
+ button_importdeepethogram = SimbaButton(parent=label_thirdpartyann, width=Formats.BUTTON_WIDTH_XS.value, txt="Import DEEPETHOGRAM Annotation (select folder with .csv files)", txt_clr="green", cmd=self.import_deepethogram, thread=False, font=Formats.FONT_REGULAR.value)
454
+ import_observer_btn = SimbaButton(parent=label_thirdpartyann, width=Formats.BUTTON_WIDTH_XS.value, txt="Import NOLDUS OBSERVER Annotation (select folder with .xls/xlsx files)", txt_clr="purple", cmd=self.import_noldus_observer, thread=False, font=Formats.FONT_REGULAR.value)
455
+
456
+
457
+ label_pseudo = CreateLabelFrameWithIcon(parent=tab7,header="PSEUDO-LABELLING", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.PSEUDO_LBL.value, bg=Formats.LABELFRAME_GREY.value, padx=5, pady=5)
458
+ pseudo_lbelling_btn = SimbaButton(parent=label_pseudo, width=Formats.BUTTON_WIDTH_XXL.value, txt="PSEUDO-LABEL VIDEO", img='label_blue', txt_clr='navy', cmd=SelectPseudoLabellingVideoPupUp, cmd_kwargs={'config_path': lambda :self.config_path}, thread=False)
459
+
460
+ label_adv_label = CreateLabelFrameWithIcon(parent=tab7, header="ADVANCED LABEL BEHAVIOR", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.ADVANCED_LBL.value, bg=Formats.LABELFRAME_GREY.value, padx=5, pady=5)
461
+
462
+ label_adv_note_1 = SimBALabel(parent=label_adv_label, txt="Note: you will have to specify the presence of *both* behavior and non-behavior on your own.", font=Formats.FONT_REGULAR.value, bg_clr=Formats.LABELFRAME_GREY.value)
463
+ label_adv_note_2 = SimBALabel(parent=label_adv_label, txt="Click here more information on how to use the SimBA labelling interface.", txt_clr='blue', cursor='hand2', font=Formats.FONT_REGULAR.value, link=Links.ADVANCED_LBL.value,bg_clr=Formats.LABELFRAME_GREY.value)
464
+
465
+ adv_label_btn_new = SimbaButton(parent=label_adv_label, width=Formats.BUTTON_WIDTH_XS.value, txt="Select video (create NEW video annotation)", cmd=select_labelling_video_advanced, cmd_kwargs={'config_path': lambda:self.config_path, 'continuing': lambda:False}, thread=False)
466
+ adv_label_btn_continue = SimbaButton(parent=label_adv_label, width=Formats.BUTTON_WIDTH_XS.value, txt="Select video (CONTINUE existing video annotation)", cmd=select_labelling_video_advanced, cmd_kwargs={'config_path': lambda:self.config_path, 'continuing': lambda:True}, thread=False)
467
+
468
+ targeted_clip_annotator_frm = CreateLabelFrameWithIcon(parent=tab7,header="TARGETED CLIP ANNOTATOR",icon_name=Keys.DOCUMENTATION.value,icon_link=Links.ADVANCED_LBL.value, bg=Formats.LABELFRAME_GREY.value, padx=5, pady=5)
469
+ targeted_clip_annotator_note = SimBALabel(parent=targeted_clip_annotator_frm, txt="A bout annotator that creates annotated clips from videos associated with ML results.", txt_clr='blue', cursor='hand2', font=Formats.FONT_REGULAR.value, link=Links.ADVANCED_LBL.value, bg_clr=Formats.LABELFRAME_GREY.value)
470
+ targeted_clip_annotator_btn = SimbaButton(parent=targeted_clip_annotator_frm, txt="Select video", cmd=select_labelling_video_targeted_clips, cmd_kwargs={'config_path': lambda:self.config_path}, thread=False)
471
+
472
+ lbl_tools_frm = CreateLabelFrameWithIcon(parent=tab7, header="LABELLING TOOLS", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.ADVANCED_LBL.value, bg=Formats.LABELFRAME_GREY.value, padx=5, pady=5)
473
+ visualize_annotation_img_btn = SimbaButton(parent=lbl_tools_frm, width=Formats.BUTTON_WIDTH_XS.value, txt="VISUALIZE ANNOTATIONS", cmd=ExtractAnnotationFramesPopUp, cmd_kwargs={'config_path': lambda:self.config_path}, thread=False)
474
+ third_party_annotations_btn = SimbaButton(parent=lbl_tools_frm, width=Formats.BUTTON_WIDTH_XS.value, txt="APPEND THIRD-PARTY ANNOTATIONS", txt_clr='purple', cmd=ThirdPartyAnnotatorAppenderPopUp, cmd_kwargs={'config_path': lambda:self.config_path}, thread=False)
475
+ remove_roi_features_from_annotation_set = SimbaButton(parent=lbl_tools_frm, width=Formats.BUTTON_WIDTH_XS.value, txt="REMOVE ROI FEATURES FROM LABEL SET", txt_clr='darkred', cmd=RemoveROIFeaturesPopUp, cmd_kwargs={'config_path': lambda:self.config_path, 'dataset': lambda:'targets_inserted'}, thread=False)
476
+ compute_annotation_statistics = SimbaButton(parent=lbl_tools_frm, width=Formats.BUTTON_WIDTH_XS.value, txt="COUNT ANNOTATIONS IN PROJECT", txt_clr='orange', cmd=ClfAnnotationCountPopUp, cmd_kwargs={'config_path': lambda:self.config_path}, thread=False)
477
+
478
+
479
+
480
+ label_trainmachinemodel = CreateLabelFrameWithIcon(parent=tab8, header="TRAIN MACHINE MODELS", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.TRAIN_ML_MODEL.value, bg=Formats.LABELFRAME_GREY.value, padx=5, pady=5)
481
+
482
+
483
+ button_trainmachinesettings = SimbaButton(parent=label_trainmachinemodel, width=Formats.BUTTON_WIDTH_XXL.value, txt="SETTINGS", img='settings', txt_clr='darkorange', cmd=self.trainmachinemodelsetting, thread=False)
484
+ button_trainmachinemodel = SimbaButton(parent=label_trainmachinemodel, width=Formats.BUTTON_WIDTH_XXL.value, txt="TRAIN SINGLE MODEL (GLOBAL ENVIRONMENT)", img='one_blue', txt_clr='blue', cmd=self.train_single_model, cmd_kwargs={'config_path': lambda:self.config_path}, thread=False)
485
+
486
+ button_train_multimodel = SimbaButton(parent=label_trainmachinemodel, width=Formats.BUTTON_WIDTH_XXL.value, txt="TRAIN MULTIPLE MODELS (ONE FOR EACH SAVED SETTING)", img='multiple_green', txt_clr='green', cmd=self.train_multiple_models_from_meta, cmd_kwargs={'config_path': lambda:self.config_path}, thread=False)
487
+
488
+ label_model_validation = CreateLabelFrameWithIcon( parent=tab9, header="VALIDATE MODEL ON SINGLE VIDEO", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.OUT_OF_SAMPLE_VALIDATION.value, padx=5, pady=5, relief='solid')
489
+ self.csvfile = FileSelect(label_model_validation,fileDescription="SELECT DATA FEATURE FILE PATH", color="blue",lblwidth=40,file_types=[("SimBA CSV", "*.csv"), ("SimBA PARQUET", "*.parquet")], initialdir=os.path.join(self.project_path, Paths.FEATURES_EXTRACTED_DIR.value))
490
+ self.modelfile = FileSelect(label_model_validation,fileDescription="SELECT MODEL FILE PATH", color="blue", lblwidth=40, initialdir=self.project_path)
491
+
492
+ button_runvalidmodel = SimbaButton(parent=label_model_validation, width=Formats.BUTTON_WIDTH_XL.value, txt="RUN MODEL", txt_clr='blue', img='rocket', cmd=self.validate_model_first_step, thread=False)
493
+ button_generateplot = SimbaButton(parent=label_model_validation, width=Formats.BUTTON_WIDTH_XL.value, txt="INTERACTIVE PROBABILITY PLOT", img='interactive_blue', txt_clr='blue', cmd=self.launch_interactive_plot, thread=False)
494
+
495
+ self.dis_threshold = Entry_Box(label_model_validation, "DISCRIMINATION THRESHOLD (0.0-1.0):", labelwidth=40, entry_box_width=30)
496
+ self.min_behaviorbout = Entry_Box(label_model_validation,"MINIMUM BOUT LENGTH (MS):",labelwidth=40, validation="numeric", entry_box_width=30)
497
+ button_validate_model = SimbaButton(parent=label_model_validation, width=Formats.BUTTON_WIDTH_XL.value, txt="CREATE VALIDATION VIDEO", txt_clr='blue', img='visualize_blue', cmd=ValidationVideoPopUp, cmd_kwargs={'config_path': lambda: config_path,
498
+ 'feature_path': lambda: self.csvfile.file_path,
499
+ 'model_path': lambda: self.modelfile.file_path,
500
+ 'discrimination_threshold': lambda: self.dis_threshold.entry_get,
501
+ 'shortest_bout': lambda: self.min_behaviorbout.entry_get})
502
+
503
+ label_runmachinemodel = CreateLabelFrameWithIcon(parent=tab9,header="RUN MACHINE MODEL",icon_name=Keys.DOCUMENTATION.value,icon_link=Links.SCENARIO_2.value, bg=Formats.LABELFRAME_GREY.value, padx=5, pady=5)
504
+
505
+ button_runmachinemodel = SimbaButton(parent=label_runmachinemodel, width=Formats.BUTTON_WIDTH_XL.value, txt="RUN MODELS", txt_clr='green', img='clf', cmd=RunMachineModelsPopUp, thread=False, cmd_kwargs={'config_path': lambda:self.config_path})
506
+
507
+ kleinberg_button = SimbaButton(parent=label_runmachinemodel, width=Formats.BUTTON_WIDTH_XL.value, txt="KLEINBERG SMOOTHING", txt_clr='green', img='feather_green', cmd=KleinbergPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
508
+ fsttc_button = SimbaButton(parent=label_runmachinemodel, width=Formats.BUTTON_WIDTH_XL.value, txt="FSTTC", txt_clr='green', img='tile_green', cmd=FSTTCPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
509
+
510
+ mutual_exclusivity = SimbaButton(parent=label_runmachinemodel, width=Formats.BUTTON_WIDTH_XL.value, txt="MUTUAL EXCLUSIVITY CORRECTION", img='seperate_green', txt_clr='green', cmd=MutualExclusivityPupUp, cmd_kwargs={'config_path': lambda:self.config_path})
511
+
512
+ label_machineresults = CreateLabelFrameWithIcon( parent=tab9, header="ANALYZE MACHINE RESULTS", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.ANALYZE_ML_RESULTS.value, bg=Formats.LABELFRAME_GREY.value, pady=5, padx=5)
513
+
514
+
515
+ button_process_datalog = SimbaButton(parent=label_machineresults, width=Formats.BUTTON_WIDTH_XL.value, txt="ANALYZE MACHINE PREDICTIONS: AGGREGATES", img='metrics_blue', txt_clr='blue', cmd=ClfDescriptiveStatsPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
516
+ button_process_movement = SimbaButton(parent=label_machineresults, width=Formats.BUTTON_WIDTH_XL.value, txt="ANALYZE DISTANCES/VELOCITY: AGGREGATES", img='metrics_blue', txt_clr='blue', cmd=MovementAnalysisPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
517
+ button_movebins = SimbaButton(parent=label_machineresults, width=Formats.BUTTON_WIDTH_XL.value, txt="ANALYZE DISTANCES/VELOCITY: TIME BINS", txt_clr='blue', img='metrics_blue', cmd=MovementAnalysisTimeBinsPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
518
+ button_classifierbins = SimbaButton(parent=label_machineresults, width=Formats.BUTTON_WIDTH_XL.value, txt="ANALYZE MACHINE PREDICTIONS: TIME-BINS", txt_clr='blue', img='metrics_blue', cmd=TimeBinsClfPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
519
+ button_classifier_ROI = SimbaButton(parent=label_machineresults, width=Formats.BUTTON_WIDTH_XL.value, txt="ANALYZE MACHINE PREDICTION: BY ROI", txt_clr='blue', img='metrics_blue', cmd=ClfByROIPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
520
+ button_severity = SimbaButton(parent=label_machineresults, width=Formats.BUTTON_WIDTH_XL.value, txt="ANALYZE MACHINE PREDICTION: BY SEVERITY", txt_clr='blue', img='metrics_blue', cmd=AnalyzeSeverityPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
521
+
522
+ visualization_frm = CreateLabelFrameWithIcon(parent=tab10, header="DATA VISUALIZATIONS", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.VISUALIZATION.value, bg=Formats.LABELFRAME_GREY.value, padx=5, pady=5)
523
+ sklearn_visualization_btn = SimbaButton(parent=visualization_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="VISUALIZE CLASSIFICATIONS", img='split', txt_clr='black', cmd=SklearnVisualizationPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
524
+ sklearn_visualization_btn.grid(row=0, column=0, sticky=NW)
525
+ gantt_visualization_btn = SimbaButton(parent=visualization_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="VISUALIZE GANTT", img='bar_graph_blue', txt_clr='blue', cmd=GanttPlotPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
526
+ gantt_visualization_btn.grid(row=1, column=0, sticky=NW)
527
+ probability_visualization_btn = SimbaButton(parent=visualization_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="VISUALIZE PROBABILITIES", img='dice_green', txt_clr='green', cmd=VisualizeClassificationProbabilityPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
528
+ probability_visualization_btn.grid(row=2, column=0, sticky=NW)
529
+ path_visualization_btn = SimbaButton(parent=visualization_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="VISUALIZE PATHS", img='path', txt_clr='navy', cmd=PathPlotPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
530
+ path_visualization_btn.grid(row=3, column=0, sticky=NW)
531
+ distance_visualization_btn = SimbaButton(parent=visualization_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="VISUALIZE DISTANCES", img='distance_red', txt_clr='red', cmd=DistancePlotterPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
532
+ distance_visualization_btn.grid(row=4, column=0, sticky=NW)
533
+ heatmap_clf_visualization_btn = SimbaButton(parent=visualization_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="VISUALIZE CLASSIFICATION HEATMAPS", img='heatmap', txt_clr='green', cmd=HeatmapClfPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
534
+ heatmap_clf_visualization_btn.grid(row=5, column=0, sticky=NW)
535
+ #data_plot_visualization_btn = SimbaButton(parent=visualization_frm, txt="VISUALIZE DATA PLOTS", img='metrics', txt_clr='purple', cmd=Nne, cmd_kwargs={'config_path': lambda:self.config_path})
536
+ data_plot_visualization_btn = SimbaButton(parent=visualization_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="VISUALIZE DATA PLOTS", img='metrics', txt_clr='purple', cmd=DataPlotterPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
537
+
538
+
539
+ data_plot_visualization_btn.grid(row=6, column=0, sticky=NW)
540
+ clf_validation_btn = SimbaButton(parent=visualization_frm, width=Formats.BUTTON_WIDTH_XL.value, txt="CLASSIFIER VALIDATION CLIPS", txt_clr='blue', img='check_blue', cmd=ClassifierValidationPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
541
+ clf_validation_btn.grid(row=7, column=0, sticky=NW)
542
+ merge_frm = CreateLabelFrameWithIcon(parent=tab10, header="MERGE FRAMES", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.CONCAT_VIDEOS.value)
543
+ merge_frm_btn = SimbaButton(parent=merge_frm, txt="MERGE FRAMES", img='merge', txt_clr='black', cmd=ConcatenatorPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
544
+ plotlyInterface = CreateLabelFrameWithIcon(parent=tab10, header="PLOTLY / DASH", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.PLOTLY.value)
545
+ plotlyInterfaceTitles = ["Sklearn results", "Time bin analyses", "Probabilities", "Severity analysis"]
546
+ toIncludeVar = []
547
+ for i in range(len(plotlyInterfaceTitles) + 1):
548
+ toIncludeVar.append(IntVar())
549
+ plotlyCheckbox = [0] * (len(plotlyInterfaceTitles) + 1)
550
+ for i in range(len(plotlyInterfaceTitles)):
551
+ plotlyCheckbox[i] = Checkbutton(plotlyInterface, text=plotlyInterfaceTitles[i], variable=toIncludeVar[i])
552
+ plotlyCheckbox[i].grid(row=i, sticky=W)
553
+
554
+ button_save_plotly_file = Button(plotlyInterface, text="Save SimBA / Plotly dataset", command=lambda: self.generateSimBPlotlyFile(toIncludeVar))
555
+ self.plotly_file = FileSelect( plotlyInterface, "SimBA Dashboard file (H5)", title="Select SimBA/Plotly dataset (h5)")
556
+ self.groups_file = FileSelect(plotlyInterface, "SimBA Groups file (CSV)", title="Select groups file (csv)")
557
+ button_open_plotly_interface = Button(plotlyInterface, text="Open SimBA / Plotly dataset", font=Formats.FONT_REGULAR.value, fg="black", command=lambda: [self.open_plotly_interface("http://127.0.0.1:8050")])
558
+
559
+
560
+ lbl_addon = CreateLabelFrameWithIcon(parent=tab11, header="SimBA EXPANSIONS", icon_name='plus_green_2')
561
+ #button_bel = SimbaButton(parent=lbl_addon, txt="Pup retrieval - Analysis Protocol 1", txt_clr='blue', cmd=None, cmd_kwargs={'config_path': lambda:self.config_path})
562
+ button_bel = SimbaButton(parent=lbl_addon, txt="PUP RETRIEVAL - ANALYSIS PROTOCOL 1", txt_clr='blue', cmd=PupRetrievalPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
563
+ #cue_light_analyser_btn = SimbaButton(parent=lbl_addon, txt="Cue light analysis", txt_clr='red', cmd=None, cmd_kwargs={'config_path': lambda:self.config_path})
564
+ cue_light_analyser_btn = SimbaButton(parent=lbl_addon, txt="CUE LIGHT ANALYSIS", txt_clr='red', img='light_bulb', cmd=CueLightMainPopUp, cmd_kwargs={'config_path': lambda:self.config_path})
565
+
566
+
567
+
568
+ anchored_roi_analysis_btn = SimbaButton(parent=lbl_addon, txt="ANIMAL-ANCHORED ROIs", txt_clr='orange', cmd=BoundaryMenus, cmd_kwargs={'config_path': lambda:self.config_path})
569
+ ImportVideosFrame(parent_frm=import_frm, config_path=config_path, idx_row=0, idx_column=0)
570
+ ImportPoseFrame(parent_frm=import_frm, idx_row=1, idx_column=0, config_path=config_path)
571
+ further_methods_frm.grid(row=0, column=1, sticky=NW, pady=10, padx=10)
572
+ extract_frm_btn.grid(row=1, column=0, sticky=NW)
573
+ import_frm_dir_btn.grid(row=2, column=0, sticky=NW)
574
+ add_clf_btn.grid(row=3, column=0, sticky=NW)
575
+ remove_clf_btn.grid(row=4, column=0, sticky=NW)
576
+ archive_files_btn.grid(row=5, column=0, sticky=NW)
577
+ reverse_btn.grid(row=6, column=0, sticky=NW)
578
+ interpolate_btn.grid(row=7, column=0, sticky=NW)
579
+ smooth_btn.grid(row=8, column=0, sticky=NW)
580
+ egocentric_align_btn.grid(row=9, column=0, sticky=NW)
581
+
582
+ label_setscale.grid(row=0, sticky=NW, pady=20, padx=20)
583
+ self.distance_in_mm_eb.grid(row=0, column=0, sticky=NW)
584
+ button_setdistanceinmm.grid(row=0, column=1, sticky=NW)
585
+ button_setscale.grid(row=1, column=0, sticky=NW)
586
+
587
+ label_outliercorrection.grid(row=0, sticky=W, padx=10, pady=10)
588
+ button_settings_outlier.grid(row=0, sticky=W)
589
+ button_outliercorrection.grid(row=1, sticky=W)
590
+ button_skipOC.grid(row=2, sticky=W, pady=5)
591
+
592
+
593
+ roi_feature_frm.grid(row=1, column=0, sticky=NW, padx=10, pady=10)
594
+ append_roi_features_by_animal.grid(row=0, column=0, sticky=NW)
595
+ append_roi_features_by_body_part.grid(row=1, column=0, sticky=NW)
596
+ remove_roi_features_from_feature_set.grid(row=2, column=0, sticky=NW)
597
+
598
+ feature_tools_frm.grid(row=2, column=0, sticky=NW, padx=10, pady=10)
599
+ compute_feature_subset_btn.grid(row=0, column=0, sticky=NW)
600
+
601
+ label_behavior_frm.grid(row=5, sticky=W, padx=10, pady=10)
602
+ select_video_btn_new.grid(row=0, sticky=W)
603
+ select_video_btn_continue.grid(row=1, sticky=W)
604
+
605
+ label_pseudo.grid(row=6, sticky=W, padx=10, pady=10)
606
+ pseudo_lbelling_btn.grid(row=0, column=0, sticky=W, pady=10)
607
+
608
+ label_adv_label.grid(row=7, column=0, sticky=NW, padx=10, pady=10)
609
+ label_adv_note_1.grid(row=0, column=0, sticky=NW)
610
+ label_adv_note_2.grid(row=1, column=0, sticky=NW)
611
+ adv_label_btn_new.grid(row=3, column=0, sticky=NW)
612
+ adv_label_btn_continue.grid(row=4, column=0, sticky=NW)
613
+
614
+ targeted_clip_annotator_frm.grid(row=8, column=0, sticky=NW, padx=10, pady=10)
615
+ targeted_clip_annotator_note.grid(row=0, column=0, sticky=NW)
616
+ targeted_clip_annotator_btn.grid(row=1, column=0, sticky=NW)
617
+
618
+ label_thirdpartyann.grid(row=9, sticky=W, padx=10, pady=10)
619
+ button_importmars.grid(row=0, column=0, sticky=NW)
620
+ button_importboris.grid(row=1, column=0, sticky=NW)
621
+ button_importsolomon.grid(row=2, column=0, sticky=NW)
622
+ button_importethovision.grid(row=0, column=1, sticky=NW)
623
+ button_importdeepethogram.grid(row=1, column=1, sticky=NW)
624
+ import_observer_btn.grid(row=2, column=1, sticky=NW)
625
+
626
+ lbl_tools_frm.grid(row=10, column=0, sticky=NW, padx=10, pady=10)
627
+ visualize_annotation_img_btn.grid(row=0, column=0, sticky=NW)
628
+ third_party_annotations_btn.grid(row=0, column=1, sticky=NW)
629
+ remove_roi_features_from_annotation_set.grid(row=1, column=0, sticky=NW)
630
+ compute_annotation_statistics.grid(row=1, column=1, sticky=NW)
631
+
632
+ label_trainmachinemodel.grid(row=6, sticky=W, padx=10, pady=10)
633
+ button_trainmachinesettings.grid(row=0, column=0, sticky=NW, padx=5)
634
+ button_trainmachinemodel.grid(row=1, column=0, sticky=NW, padx=5)
635
+ button_train_multimodel.grid(row=2, column=0, sticky=NW, padx=5)
636
+
637
+ label_model_validation.grid(row=7, sticky=W, pady=10, padx=10)
638
+ self.csvfile.grid(row=0, sticky=W)
639
+ self.modelfile.grid(row=1, sticky=W)
640
+ button_runvalidmodel.grid(row=2, sticky=W)
641
+ button_generateplot.grid(row=3, sticky=W)
642
+ self.dis_threshold.grid(row=4, sticky=W)
643
+ self.min_behaviorbout.grid(row=5, sticky=W)
644
+ button_validate_model.grid(row=6, sticky=W)
645
+
646
+ label_runmachinemodel.grid(row=8, sticky=NW, padx=10, pady=10)
647
+ button_runmachinemodel.grid(row=0, sticky=NW)
648
+ kleinberg_button.grid(row=1, sticky=NW)
649
+ fsttc_button.grid(row=2, sticky=NW)
650
+ mutual_exclusivity.grid(row=3, sticky=NW)
651
+
652
+ label_machineresults.grid(row=9, sticky=W, padx=10, pady=10)
653
+ button_process_datalog.grid(row=2, column=0, sticky=W, padx=3)
654
+ button_process_movement.grid(row=2, column=1, sticky=W, padx=3)
655
+ button_movebins.grid(row=3, column=1, sticky=W, padx=3)
656
+ button_classifierbins.grid(row=3, column=0, sticky=W, padx=3)
657
+ button_classifier_ROI.grid(row=4, column=0, sticky=W, padx=3)
658
+ button_severity.grid(row=4, column=1, sticky=W, padx=3)
659
+
660
+ visualization_frm.grid(row=11, column=0, sticky=W + N, padx=10, pady=10)
661
+ merge_frm.grid(row=11, column=2, sticky=W + N, padx=5)
662
+ merge_frm_btn.grid(row=0, sticky=NW, padx=5)
663
+
664
+ plotlyInterface.grid(row=11, column=3, sticky=W + N, padx=5)
665
+ button_save_plotly_file.grid(row=10, sticky=W)
666
+ self.plotly_file.grid(row=11, sticky=W)
667
+ self.groups_file.grid(row=12, sticky=W)
668
+ button_open_plotly_interface.grid(row=13, sticky=W)
669
+
670
+ lbl_addon.grid(row=0, sticky=W)
671
+ button_bel.grid(row=0, sticky=W)
672
+ cue_light_analyser_btn.grid(row=1, sticky=NW)
673
+ anchored_roi_analysis_btn.grid(row=2, sticky=NW)
674
+
675
+ if ENV[ENV_VARS.UNSUPERVISED_INTERFACE.value]:
676
+ from simba.unsupervised.unsupervised_main import UnsupervisedGUI
677
+ unsupervised_btn = Button(lbl_addon, text="Unsupervised analysis", fg="purple", font=Formats.FONT_REGULAR.value, command=lambda: UnsupervisedGUI(config_path=self.config_path))
678
+ unsupervised_btn.grid(row=3, sticky=NW)
679
+ write_to_recent_project_paths(config_path=self.config_path)
680
+
681
+ def create_video_info_table(self):
682
+ video_info_tabler = VideoInfoTable(config_path=self.config_path)
683
+ video_info_tabler.run()
684
+
685
+ def initiate_skip_outlier_correction(self):
686
+ outlier_correction_skipper = OutlierCorrectionSkipper(config_path=self.config_path)
687
+ outlier_correction_skipper.run()
688
+
689
+ def validate_model_first_step(self):
690
+ _ = InferenceValidation(config_path=self.config_path, input_file_path=self.csvfile.file_path, clf_path=self.modelfile.file_path)
691
+
692
+ def train_single_model(self, config_path=None):
693
+ model_trainer = TrainRandomForestClassifier(config_path=config_path)
694
+ model_trainer.run()
695
+ model_trainer.save()
696
+
697
+ def train_multiple_models_from_meta(self, config_path=None):
698
+ model_trainer = GridSearchRandomForestClassifier(config_path=config_path)
699
+ model_trainer.run()
700
+
701
+ def importBoris(self):
702
+ ann_folder = askdirectory()
703
+ boris_appender = BorisAppender(config_path=self.config_path, data_dir=ann_folder)
704
+ threading.Thread(target=boris_appender.run).start()
705
+
706
+ def importSolomon(self):
707
+ ann_folder = askdirectory()
708
+ solomon_importer = SolomonImporter(config_path=self.config_path, data_dir=ann_folder)
709
+ threading.Thread(target=solomon_importer.run).start()
710
+
711
+ def import_ethovision(self):
712
+ ann_folder = askdirectory()
713
+ ethovision_importer = ImportEthovision(config_path=self.config_path, data_dir=ann_folder)
714
+ threading.Thread(target=ethovision_importer.run).start()
715
+
716
+ def import_deepethogram(self):
717
+ ann_folder = askdirectory()
718
+ deepethogram_importer = DeepEthogramImporter(config_path=self.config_path, data_dir=ann_folder)
719
+ if self.core_cnt > Defaults.THREADSAFE_CORE_COUNT.value:
720
+ deepethogram_importer.run()
721
+ else:
722
+ threading.Thread(target=deepethogram_importer.run).start()
723
+
724
+ def import_noldus_observer(self):
725
+ directory = askdirectory()
726
+ noldus_observer_importer = NoldusObserverImporter(config_path=self.config_path, data_dir=directory)
727
+ threading.Thread(target=noldus_observer_importer.run).start()
728
+
729
+ def importMARS(self):
730
+ bento_dir = askdirectory()
731
+ bento_appender = BentoAppender(config_path=self.config_path, data_dir=bento_dir)
732
+ threading.Thread(target=bento_appender.run).start()
733
+
734
+ def launch_interactive_plot(self):
735
+ interactive_grapher = InteractiveProbabilityGrapher(config_path=self.config_path,file_path=self.csvfile.file_path,model_path=self.modelfile.file_path)
736
+ interactive_grapher.run()
737
+
738
+ def generateSimBPlotlyFile(self, var):
739
+ inputList = []
740
+ for i in var:
741
+ inputList.append(i.get())
742
+ stdout_warning(msg="SimBA plotly interface is not available.")
743
+ pass
744
+
745
+ def open_plotly_interface(self, url):
746
+ try:
747
+ self.p.kill()
748
+ self.p2.kill()
749
+ except:
750
+ print("Starting plotly")
751
+ # get h5 file path and csv file path
752
+ filePath, groupPath = self.plotly_file.file_path, self.groups_file.file_path
753
+
754
+ # print file read
755
+ if filePath.endswith(".h5"):
756
+ print("Reading in", os.path.basename(filePath))
757
+ elif groupPath.endswith(".csv"):
758
+ print("Reading in", os.path.basename(groupPath))
759
+
760
+ self.p = subprocess.Popen(
761
+ [
762
+ sys.executable,
763
+ os.path.join(
764
+ os.path.dirname(__file__), "dash_app", "SimBA_dash_app.py"
765
+ ),
766
+ filePath,
767
+ groupPath,
768
+ ]
769
+ )
770
+ # csvPath = os.path.join(os.path.dirname(self.config_path),'csv')
771
+ # p = subprocess.Popen([sys.executable, r'simba\SimBA_dash_app.py', filePath, groupPath, csvPath])
772
+ wait_for_internet_connection(url)
773
+ self.p2 = subprocess.Popen(
774
+ [
775
+ sys.executable,
776
+ os.path.join(
777
+ os.path.dirname(__file__), "dash_app", "run_dash_tkinter.py"
778
+ ),
779
+ url,
780
+ ]
781
+ )
782
+ subprocess_children = [self.p, self.p2]
783
+ atexit.register(terminate_children, subprocess_children)
784
+
785
+ def trainmachinemodelsetting(self):
786
+ _ = MachineModelSettingsPopUp(config_path=self.config_path)
787
+
788
+ def run_feature_extraction(self):
789
+ print(f"Running feature extraction... start time: {get_current_time()}")
790
+ feature_extractor_classes = get_bp_config_code_class_pairs()
791
+ if self.user_defined_var.get():
792
+ custom_feature_extractor = CustomFeatureExtractor(extractor_file_path=self.scriptfile.file_path,config_path=self.config_path)
793
+ custom_feature_extractor.run()
794
+ stdout_success(msg="Custom feature extraction complete!",source=self.__class__.__name__)
795
+ else:
796
+ print(f"Pose-estimation body part setting for feature extraction: {str(self.animal_cnt)} animals {str(self.pose_setting)} body-parts...")
797
+ if self.pose_setting not in feature_extractor_classes.keys():
798
+ raise InvalidInputError(msg=f"The project pose-configuration key is set to {self.pose_setting} which is invalid. OPTIONS: {list(feature_extractor_classes.keys())}. Check the pose-estimation setting in the project_config.ini", source=self.__class__.__name__)
799
+ if self.pose_setting == "8":
800
+ feature_extractor = feature_extractor_classes[self.pose_setting][self.animal_cnt](config_path=self.config_path)
801
+ else:
802
+ feature_extractor = feature_extractor_classes[self.pose_setting](config_path=self.config_path)
803
+ feature_extractor.run()
804
+
805
+ def set_distance_mm(self):
806
+ check_int(name="DISTANCE IN MILLIMETER",value=self.distance_in_mm_eb.entry_get,min_value=1)
807
+ self.config.set("Frame settings", "distance_mm", self.distance_in_mm_eb.entry_get)
808
+ with open(self.config_path, "w") as f:
809
+ self.config.write(f)
810
+
811
+ def correct_outlier(self):
812
+ outlier_correcter_movement = OutlierCorrecterMovement(config_path=self.config_path)
813
+ outlier_correcter_movement.run()
814
+ outlier_correcter_location = OutlierCorrecterLocation(config_path=self.config_path)
815
+ outlier_correcter_location.run()
816
+ stdout_success(msg='Outlier corrected files located in "project_folder/csv/outlier_corrected_movement_location" directory',source=self.__class__.__name__)
817
+
818
+ def callback(self, url):
819
+ webbrowser.open_new(url)
820
+
821
+
822
+ class App(object):
823
+ def __init__(self):
824
+ bg_path = os.path.join(os.path.dirname(__file__), Paths.BG_IMG_PATH.value)
825
+ emojis = get_emojis()
826
+ icon_path_windows = os.path.join(os.path.dirname(__file__), Paths.LOGO_ICON_WINDOWS_PATH.value)
827
+ icon_path_darwin = os.path.join(os.path.dirname(__file__), Paths.LOGO_ICON_DARWIN_PATH.value)
828
+ self.menu_icons = get_icons_paths()
829
+ recent_project_paths = get_recent_projects_paths()
830
+ self.root = Tk()
831
+ self.root.title("SimBA")
832
+ self.root.minsize(750, 750)
833
+ self.root.geometry(Formats.ROOT_WINDOW_SIZE.value)
834
+ self.root.rowconfigure(0, weight=1)
835
+ self.root.columnconfigure(0, weight=1)
836
+ if currentPlatform == OS.WINDOWS.value:
837
+ load_simba_fonts()
838
+ self.root.iconbitmap(icon_path_windows)
839
+ if currentPlatform == OS.MAC.value:
840
+ load_simba_fonts()
841
+ self.root.iconphoto(False, ImageTk.PhotoImage(PIL.Image.open(icon_path_darwin)))
842
+ for k in self.menu_icons.keys():
843
+ self.menu_icons[k]["img"] = ImageTk.PhotoImage(image=PIL.Image.open(os.path.join(os.path.dirname(__file__), self.menu_icons[k]["icon_path"])))
844
+ bg_img = ImageTk.PhotoImage(file=bg_path)
845
+ background = Label(self.root, image=bg_img, bd=0, bg="white")
846
+ background.pack(fill="both", expand=True)
847
+ background.image = bg_img
848
+
849
+ ultralytics_version = get_pkg_version(pkg=PackageNames.ULTRALYTICS.value)
850
+ yolo_state = DISABLED if ultralytics_version is None else NORMAL
851
+
852
+
853
+ menu = Menu(self.root)
854
+ self.root.config(menu=menu)
855
+ self.file_menu = Menu(menu)
856
+ menu.add_cascade(label="File", menu=self.file_menu)
857
+ self.file_menu.add_command(label="Create a new project", compound="left", image=self.menu_icons["create"]["img"], command=lambda: ProjectCreatorPopUp(), font=Formats.FONT_REGULAR.value)
858
+ self.file_menu.add_command(label="Load project", compound="left", image=self.menu_icons["load"]["img"], command=lambda: LoadProjectPopUp(), font=Formats.FONT_REGULAR.value)
859
+ self.file_menu.add_separator()
860
+ self.recent_projects_menu = Menu(menu)
861
+
862
+ for recent_project_path in recent_project_paths:
863
+ self.recent_projects_menu.add_command(label=recent_project_path,command=lambda p=recent_project_path: SimbaProjectPopUp(config_path=p), font=Formats.FONT_REGULAR.value)
864
+ self.recent_projects_menu.add_command(label='Clear recent projects', command=lambda: self.clear_recent_projects(), font=Formats.FONT_REGULAR_ITALICS.value)
865
+ recent_project_state = DISABLED if len(recent_project_paths) == 0 else NORMAL
866
+ self.file_menu.add_cascade(label="Open recent project...", compound="left", image=self.menu_icons["recent_files"]["img"], menu=self.recent_projects_menu, font=Formats.FONT_REGULAR.value, state=recent_project_state)
867
+
868
+ self.file_menu.add_separator()
869
+ self.file_menu.add_command(label="Restart", compound="left", image=self.menu_icons["restart"]["img"], command=lambda: self.restart(), font=Formats.FONT_REGULAR.value)
870
+ self.file_menu.add_separator()
871
+ self.file_menu.add_command(label="Exit", compound="left", image=self.menu_icons["exit"]["img"], command=self.root.destroy, font=Formats.FONT_REGULAR.value)
872
+
873
+ batch_process_menu = Menu(menu)
874
+ menu.add_cascade(label="Process Videos", menu=batch_process_menu)
875
+ batch_process_menu.add_command(label="Batch pre-process videos", compound="left", image=self.menu_icons["factory"]["img"], command=lambda: BatchPreProcessPopUp(), font=Formats.FONT_REGULAR.value)
876
+
877
+ blob_tracking_menu = Menu(batch_process_menu)
878
+ blob_tracking_menu.add_command(label="Perform blob tracking", compound="left", image=self.menu_icons["bubble_green"]["img"], command=InitializeBlobTrackerPopUp, font=Formats.FONT_REGULAR.value)
879
+ blob_tracking_menu.add_command(label="Visualize blob tracking", compound="left", image=self.menu_icons["bubble_pink"]["img"], command=BlobVisualizerPopUp, font=Formats.FONT_REGULAR.value)
880
+ batch_process_menu.add_cascade(label="Blob tracking...", compound="left", image=self.menu_icons["bubble"]["img"], menu=blob_tracking_menu, font=Formats.FONT_REGULAR.value)
881
+
882
+ yolo_tracking_menu = Menu(batch_process_menu)
883
+ yolo_tracking_menu.add_command(label="Train YOLO model", compound="left", image=self.menu_icons["ultralytics_2"]["img"], command=YOLOPoseTrainPopUP, font=Formats.FONT_REGULAR.value, state=yolo_state)
884
+ yolo_tracking_menu.add_command(label="Predict with YOLO model", compound="left", image=self.menu_icons["ultralytics_2"]["img"], command=YOLOPoseInferencePopUP, font=Formats.FONT_REGULAR.value, state=yolo_state)
885
+ yolo_tracking_menu.add_command(label="Visualize YOLO model results", compound="left", image=self.menu_icons["ultralytics_2"]["img"], command=YoloPoseVisualizerPopUp, font=Formats.FONT_REGULAR.value, state=yolo_state)
886
+ batch_process_menu.add_cascade(label="YOLO tracking...", compound="left", image=self.menu_icons["ultralytics_2"]["img"], menu=yolo_tracking_menu, font=Formats.FONT_REGULAR.value, state=yolo_state)
887
+
888
+ video_process_menu = Menu(menu)
889
+ fps_menu = Menu(video_process_menu)
890
+ fps_menu.add_command(label="Change FPS for single video", compound="left", image=self.menu_icons["single_blue"]["img"], command=ChangeFpsSingleVideoPopUp, font=Formats.FONT_REGULAR.value)
891
+ fps_menu.add_command(label="Change FPS for multiple videos", compound="left", image=self.menu_icons["multiple_blue"]["img"], command=ChangeFpsMultipleVideosPopUp, font=Formats.FONT_REGULAR.value)
892
+ fps_menu.add_command(label="Up-sample fps with interpolation", command=UpsampleVideosPopUp, font=Formats.FONT_REGULAR.value)
893
+
894
+ menu.add_cascade(label="Tools", menu=video_process_menu)
895
+ video_process_menu.add_cascade(label="Change FPS...", compound="left", image=self.menu_icons["fps"]["img"], menu=fps_menu, font=Formats.FONT_REGULAR.value)
896
+
897
+ clip_video_menu = Menu(menu)
898
+ clip_video_menu.add_command(label="Clip single video", command=ClipVideoPopUp, font=Formats.FONT_REGULAR.value, image=self.menu_icons["video_2"]["img"], compound="left",)
899
+ clip_video_menu.add_command(label="Clip multiple videos", command=InitiateClipMultipleVideosByTimestampsPopUp, font=Formats.FONT_REGULAR.value, image=self.menu_icons["stack"]["img"], compound="left",)
900
+
901
+ clip_video_menu.add_command(label="Clip video into multiple videos", command=MultiShortenPopUp, font=Formats.FONT_REGULAR.value, image=self.menu_icons["one_to_many"]["img"], compound="left",)
902
+ clip_video_menu.add_command(label="Clip single video by frame numbers", command=ClipSingleVideoByFrameNumbers, font=Formats.FONT_REGULAR.value, image=self.menu_icons["video_2"]["img"], compound="left",)
903
+ clip_video_menu.add_command(label="Clip multiple videos by frame numbers", command=InitiateClipMultipleVideosByFrameNumbersPopUp, font=Formats.FONT_REGULAR.value, image=self.menu_icons["stack"]["img"], compound="left",)
904
+
905
+ video_process_menu.add_cascade(label="Clip videos...", compound="left", image=self.menu_icons["clip"]["img"], menu=clip_video_menu, font=Formats.FONT_REGULAR.value)
906
+
907
+ crop_video_menu = Menu(menu)
908
+ crop_video_menu.add_command(label="Crop videos", compound="left", image=self.menu_icons["crop"]["img"], command=CropVideoPopUp, font=Formats.FONT_REGULAR.value)
909
+ crop_video_menu.add_command(label="Crop videos (circles)", compound="left", image=self.menu_icons["circle"]["img"], command=CropVideoCirclesPopUp, font=Formats.FONT_REGULAR.value)
910
+ crop_video_menu.add_command(label="Crop videos (polygons)", compound="left", image=self.menu_icons["polygon"]["img"], command=CropVideoPolygonsPopUp, font=Formats.FONT_REGULAR.value)
911
+ crop_video_menu.add_command(label="Multi-crop", compound="left", image=self.menu_icons["crop"]["img"], command=MultiCropPopUp, font=Formats.FONT_REGULAR.value)
912
+ video_process_menu.add_cascade(label="Crop videos...", compound="left", image=self.menu_icons["crop"]["img"], menu=crop_video_menu, font=Formats.FONT_REGULAR.value)
913
+
914
+ format_menu = Menu(video_process_menu)
915
+ img_format_menu = Menu(format_menu)
916
+ video_format_menu = Menu(format_menu)
917
+
918
+
919
+
920
+ img_format_menu.add_command(label="Convert images to PNG", compound="left", image=self.menu_icons["png"]["img"], command=Convert2PNGPopUp, font=Formats.FONT_REGULAR.value)
921
+ img_format_menu.add_command(label="Convert images to JPEG", compound="left", image=self.menu_icons["jpeg"]["img"], command=Convert2jpegPopUp, font=Formats.FONT_REGULAR.value)
922
+ img_format_menu.add_command(label="Convert images to BMP", compound="left", image=self.menu_icons["bmp"]["img"], command=Convert2bmpPopUp, font=Formats.FONT_REGULAR.value)
923
+ img_format_menu.add_command(label="Convert images to TIFF", compound="left", image=self.menu_icons["tiff"]["img"], command=Convert2TIFFPopUp, font=Formats.FONT_REGULAR.value)
924
+ img_format_menu.add_command(label="Convert images to WEBP", compound="left", image=self.menu_icons["webp"]["img"], command=Convert2WEBPPopUp, font=Formats.FONT_REGULAR.value)
925
+ video_format_menu.add_command(label="Convert videos to MP4", compound="left", image=self.menu_icons["mp4"]["img"], command=Convert2MP4PopUp, font=Formats.FONT_REGULAR.value)
926
+ video_format_menu.add_command(label="Convert videos to AVI", compound="left", image=self.menu_icons["avi"]["img"], command=Convert2AVIPopUp, font=Formats.FONT_REGULAR.value)
927
+ video_format_menu.add_command(label="Convert videos to WEBM", compound="left", image=self.menu_icons["webm"]["img"], command=Convert2WEBMPopUp, font=Formats.FONT_REGULAR.value)
928
+ video_format_menu.add_command(label="Convert videos to MOV", compound="left", image=self.menu_icons["mov"]["img"], command=Convert2MOVPopUp, font=Formats.FONT_REGULAR.value)
929
+ format_menu.add_cascade(label="Convert image file formats...", compound="left", image=self.menu_icons["image"]["img"], menu=img_format_menu, font=Formats.FONT_REGULAR.value)
930
+ format_menu.add_cascade(label="Change video file formats...", compound="left", image=self.menu_icons["video_2"]["img"], menu=video_format_menu, font=Formats.FONT_REGULAR.value)
931
+ video_process_menu.add_cascade(label="Convert file formats...", compound="left", image=self.menu_icons["convert"]["img"], menu=format_menu, font=Formats.FONT_REGULAR.value)
932
+
933
+ rm_clr_menu = Menu(video_process_menu)
934
+ rm_clr_menu.add_command(label="Convert to grayscale", compound="left", image=self.menu_icons["greyscale"]["img"], command=lambda: GreyscaleSingleVideoPopUp(), font=Formats.FONT_REGULAR.value)
935
+ rm_clr_menu.add_command(label="Convert to black and white", compound="left", image=self.menu_icons["bw"]["img"], command=Convert2BlackWhitePopUp, font=Formats.FONT_REGULAR.value)
936
+ rm_clr_menu.add_command(label="CLAHE enhance videos", compound="left", image=self.menu_icons["clahe"]["img"], command=CLAHEPopUp, font=Formats.FONT_REGULAR.value)
937
+ rm_clr_menu.add_command(label="Interactively CLAHE enhance videos", compound="left", image=self.menu_icons["clahe"]["img"], command=InteractiveClahePopUp, font=Formats.FONT_REGULAR.value)
938
+ video_process_menu.add_cascade(label="Remove color from videos...", compound="left", image=self.menu_icons["clahe"]["img"], menu=rm_clr_menu, font=Formats.FONT_REGULAR.value)
939
+
940
+ concatenate_menu = Menu(video_process_menu)
941
+ concatenate_menu.add_command(label="Concatenate two videos", compound="left", image=self.menu_icons["concat"]["img"], command=ConcatenatingVideosPopUp, font=Formats.FONT_REGULAR.value)
942
+ concatenate_menu.add_command(label="Concatenate multiple videos", compound="left", image=self.menu_icons["concat_videos"]["img"], command=lambda: ConcatenatorPopUp(config_path=None), font=Formats.FONT_REGULAR.value)
943
+ video_process_menu.add_cascade(label="Concatenate (stack) videos...", compound="left", image=self.menu_icons["concat"]["img"], menu=concatenate_menu, font=Formats.FONT_REGULAR.value)
944
+ video_process_menu.add_command(label="Convert ROI definitions", compound="left", image=self.menu_icons["roi"]["img"], command=lambda: ConvertROIDefinitionsPopUp(), font=Formats.FONT_REGULAR.value)
945
+
946
+ convert_pose_file_format_menu = Menu(video_process_menu)
947
+ convert_pose_file_format_menu.add_command(label="COCO key-points -> YOLO key-points", compound="left", image=self.menu_icons["coco_small"]["img"], command=COCOKeypoints2YOLOkeypointsPopUp, font=Formats.FONT_REGULAR.value)
948
+ convert_pose_file_format_menu.add_command(label="COCO key-point files (multiple) -> COCO key-point file (single)", compound="left", image=self.menu_icons["coco_small"]["img"], command=MergeCOCOKeypointFilesPopUp, font=Formats.FONT_REGULAR.value)
949
+ convert_pose_file_format_menu.add_command(label="DLC annotations -> Labelme key-points", compound="left", image=self.menu_icons["dlc_2"]["img"], command=DLC2LabelmePopUp, font=Formats.FONT_REGULAR.value)
950
+ convert_pose_file_format_menu.add_command(label="DLC annotations -> YOLO pose-estimation annotations", compound="left", image=self.menu_icons["dlc_2"]["img"], command=DLCYoloKeypointsPopUp, font=Formats.FONT_REGULAR.value)
951
+ convert_pose_file_format_menu.add_command(label="DLC H5 inference -> YOLO pose-estimation annotations", compound="left", image=self.menu_icons["dlc_2"]["img"], command=DLCH5Inference2YoloPopUp, font=Formats.FONT_REGULAR.value)
952
+ convert_pose_file_format_menu.add_command(label="SLEAP CSV inference -> YOLO pose-estimation annotations", compound="left", image=self.menu_icons["sleap_small"]["img"], command=SLEAPcsvInference2Yolo, font=Formats.FONT_REGULAR.value)
953
+ convert_pose_file_format_menu.add_command(label="SLEAP H5 inference -> YOLO pose-estimation annotations", compound="left", image=self.menu_icons["sleap_small"]["img"], command=SLEAPH5Inference2YoloPopUp, font=Formats.FONT_REGULAR.value)
954
+ convert_pose_file_format_menu.add_command(label="SLEAP SLP annotations -> YOLO pose-estimation annotations", compound="left", image=self.menu_icons["sleap_small"]["img"], command=SLEAPAnnotations2YoloPopUp, font=Formats.FONT_REGULAR.value)
955
+ convert_pose_file_format_menu.add_command(label="SimBA ROI -> YOLO bounding-box annotations", compound="left", image=self.menu_icons["SimBA_logo_3_small"]["img"], command=SimBAROIs2YOLOPopUp, font=Formats.FONT_REGULAR.value)
956
+ convert_pose_file_format_menu.add_command(label="SimBA -> YOLO pose-estimation annotations", compound="left", image=self.menu_icons["SimBA_logo_3_small"]["img"], command=SimBA2YoloKeypointsPopUp, font=Formats.FONT_REGULAR.value)
957
+ convert_pose_file_format_menu.add_command(label="Labelme key-points -> Images", compound="left", image=self.menu_icons["labelme"]["img"], command=Labelme2ImgsPopUp, font=Formats.FONT_REGULAR.value)
958
+ convert_pose_file_format_menu.add_command(label="Labelme key-points -> CSV", compound="left", image=self.menu_icons["labelme"]["img"], command=Labelme2DataFramePopUp, font=Formats.FONT_REGULAR.value)
959
+ convert_pose_file_format_menu.add_command(label="Labelme bounding-boxes -> YOLO bounding-box annotations", compound="left", image=self.menu_icons["labelme"]["img"], command=LabelmeBbox2YoloBboxPopUp, font=Formats.FONT_REGULAR.value)
960
+
961
+ video_process_menu.add_cascade(label="Convert tracking data formats...", compound="left", image=self.menu_icons["pose"]["img"], menu=convert_pose_file_format_menu, font=Formats.FONT_REGULAR.value)
962
+
963
+ convert_data_menu = Menu(video_process_menu)
964
+ convert_data_menu.add_command(label="Convert CSV to parquet", compound="left", image=self.menu_icons["parquet"]["img"], command=Csv2ParquetPopUp, font=Formats.FONT_REGULAR.value)
965
+ convert_data_menu.add_command(label="Convert parquet to CSV", compound="left", image=self.menu_icons["csv_grey"]["img"], command=Parquet2CsvPopUp, font=Formats.FONT_REGULAR.value)
966
+ video_process_menu.add_cascade(label="Convert working file type...", compound="left", image=self.menu_icons["change"]["img"], menu=convert_data_menu, font=Formats.FONT_REGULAR.value)
967
+ video_process_menu.add_command(label="Create path plot", compound="left", image=self.menu_icons["path"]["img"], command=MakePathPlotPopUp, font=Formats.FONT_REGULAR.value)
968
+
969
+ downsample_video_menu = Menu(video_process_menu)
970
+ downsample_video_menu.add_command(label="Down-sample single video", compound="left", image=self.menu_icons["single_green"]["img"], command=DownsampleSingleVideoPopUp, font=Formats.FONT_REGULAR.value)
971
+ downsample_video_menu.add_command(label="Down-sample multiple videos", compound="left", image=self.menu_icons["multiple_green"]["img"], command=DownsampleMultipleVideosPopUp, font=Formats.FONT_REGULAR.value)
972
+ video_process_menu.add_cascade(label="Down-sample video...", compound="left", image=self.menu_icons["sample"]["img"], menu=downsample_video_menu, font=Formats.FONT_REGULAR.value)
973
+ video_process_menu.add_cascade(label="Drop body-parts from tracking data", compound="left", image=self.menu_icons["trash"]["img"], command=DropTrackingDataPopUp, font=Formats.FONT_REGULAR.value)
974
+ extract_frames_menu = Menu(video_process_menu, font=Formats.FONT_REGULAR.value)
975
+ extract_frames_menu.add_command(label="Extract defined frames", command=ExtractSpecificFramesPopUp, font=Formats.FONT_REGULAR.value, image=self.menu_icons["frames"]["img"], compound="left")
976
+ extract_frames_menu.add_command(label="Extract frames from single video", command=SingleVideo2FramesPopUp, font=Formats.FONT_REGULAR.value, image=self.menu_icons["frames_2"]["img"], compound="left")
977
+ extract_frames_menu.add_command(label="Extract frames from multiple videos", command=MultipleVideos2FramesPopUp, font=Formats.FONT_REGULAR.value, image=self.menu_icons["stack"]["img"], compound="left")
978
+ extract_frames_menu.add_command(label="Extract frames from seq files", command=ExtractSEQFramesPopUp, font=Formats.FONT_REGULAR.value, image=self.menu_icons["fire"]["img"], compound="left")
979
+ video_process_menu.add_cascade(label="Extract frames...", compound="left", image=self.menu_icons["frames"]["img"], menu=extract_frames_menu, font=Formats.FONT_REGULAR.value)
980
+
981
+ video_process_menu.add_command(label="Create GIFs", compound="left", image=self.menu_icons["gif"]["img"], command=CreateGIFPopUP, font=Formats.FONT_REGULAR.value)
982
+
983
+ video_process_menu.add_command(label="Get metric conversion factor (pixels/millimeter)", compound="left", image=self.menu_icons["calipher"]["img"], command=CalculatePixelsPerMMInVideoPopUp, font=Formats.FONT_REGULAR.value)
984
+ video_process_menu.add_command(label="Change video brightness / contrast", compound="left", image=self.menu_icons["brightness"]["img"], command=BrightnessContrastPopUp, font=Formats.FONT_REGULAR.value)
985
+ video_process_menu.add_command(label="Merge frames to video", compound="left", image=self.menu_icons["merge"]["img"], command=MergeFrames2VideoPopUp, font=Formats.FONT_REGULAR.value)
986
+ video_process_menu.add_command(label="Change video playback speed", compound="left", image=self.menu_icons["run"]["img"], command=ChangeSpeedPopup, font=Formats.FONT_REGULAR.value)
987
+ video_process_menu.add_command(label="Print classifier info", compound="left", image=self.menu_icons["print"]["img"], command=PrintModelInfoPopUp, font=Formats.FONT_REGULAR.value)
988
+ video_process_menu.add_command(label="Show video file(s) meta data", compound="left", image=self.menu_icons["print"]["img"], command=PrintVideoMetaDataPopUp, font=Formats.FONT_REGULAR.value)
989
+
990
+
991
+ video_process_menu.add_cascade(label="Reorganize Tracking Data", compound="left", image=self.menu_icons["reorganize"]["img"], command=PoseReorganizerPopUp, font=Formats.FONT_REGULAR.value)
992
+
993
+ rotate_menu = Menu(menu)
994
+ rotate_menu.add_command(label="Rotate videos", compound="left", image=self.menu_icons["flip_red"]["img"], command=RotateVideoSetDegreesPopUp, font=Formats.FONT_REGULAR.value)
995
+ rotate_menu.add_command(label="Interactively rotate videos", compound="left", image=self.menu_icons["flip_red"]["img"], command=VideoRotatorPopUp, font=Formats.FONT_REGULAR.value)
996
+ rotate_menu.add_command(label="Flip videos", compound="left", image=self.menu_icons["flip_green"]["img"], command=FlipVideosPopUp, font=Formats.FONT_REGULAR.value)
997
+ rotate_menu.add_command(label="Reverse videos", compound="left", image=self.menu_icons["reverse_blue"]["img"], command=ReverseVideoPopUp, font=Formats.FONT_REGULAR.value)
998
+ video_process_menu.add_cascade(label="Rotate / flip / reverse videos...", compound="left", image=self.menu_icons["rotate"]["img"], menu=rotate_menu, font=Formats.FONT_REGULAR.value)
999
+
1000
+ superimpose_menu = Menu(menu)
1001
+ superimpose_menu.add_command(label="Superimpose frame numbers", compound="left", image=self.menu_icons["number_black"]["img"], command=SuperImposeFrameCountPopUp, font=Formats.FONT_REGULAR.value)
1002
+ superimpose_menu.add_command(label="Superimpose watermark", compound="left", image=self.menu_icons["watermark_green"]["img"], command=SuperimposeWatermarkPopUp, font=Formats.FONT_REGULAR.value)
1003
+ superimpose_menu.add_command(label="Superimpose timer", compound="left", image=self.menu_icons["timer"]["img"], command=SuperimposeTimerPopUp, font=Formats.FONT_REGULAR.value)
1004
+ superimpose_menu.add_command(label="Superimpose progress-bar", compound="left", image=self.menu_icons["progressbar_black"]["img"], command=SuperimposeProgressBarPopUp, font=Formats.FONT_REGULAR.value)
1005
+ superimpose_menu.add_command(label="Superimpose video on video", compound="left", image=self.menu_icons["video_2"]["img"], command=SuperimposeVideoPopUp, font=Formats.FONT_REGULAR.value)
1006
+ superimpose_menu.add_command(label="Superimpose video names", compound="left", image=self.menu_icons["id_card"]["img"], command=SuperimposeVideoNamesPopUp, font=Formats.FONT_REGULAR.value)
1007
+ superimpose_menu.add_command(label="Superimpose free-text", compound="left", image=self.menu_icons["text_black"]["img"], command=SuperimposeTextPopUp, font=Formats.FONT_REGULAR.value)
1008
+ video_process_menu.add_cascade(label="Superimpose on videos...", compound="left", image=self.menu_icons["superimpose"]["img"], menu=superimpose_menu, font=Formats.FONT_REGULAR.value)
1009
+
1010
+ remove_bg_menu = Menu(menu)
1011
+ remove_bg_menu.add_command(label="Remove background from single video (mean subtraction)", compound="left", image=self.menu_icons["remove_bg"]["img"], command=BackgroundRemoverSingleVideoPopUp, font=Formats.FONT_REGULAR.value)
1012
+ remove_bg_menu.add_command(label="Remove background from multiple videos (mean subtraction)", compound="left", image=self.menu_icons["remove_bg"]["img"], command=BackgroundRemoverDirectoryPopUp, font=Formats.FONT_REGULAR.value)
1013
+ video_process_menu.add_cascade(label="Remove video backgrounds...", compound="left", image=self.menu_icons["remove_bg"]["img"], menu=remove_bg_menu, font=Formats.FONT_REGULAR.value)
1014
+
1015
+ temporal_join_videos = Menu(menu)
1016
+ temporal_join_videos.add_command(label="Temporal join all videos in directory", command=VideoTemporalJoinPopUp, font=Formats.FONT_REGULAR.value)
1017
+ temporal_join_videos.add_command(label="Temporal join selected videos", command=ManualTemporalJoinPopUp, font=Formats.FONT_REGULAR.value)
1018
+ video_process_menu.add_cascade(label="Temporal join videos...", compound="left", image=self.menu_icons["stopwatch"]["img"], menu=temporal_join_videos, font=Formats.FONT_REGULAR.value)
1019
+ video_process_menu.add_command(label="Box blur videos", compound="left", image=self.menu_icons["blur"]["img"], command=BoxBlurPopUp, font=Formats.FONT_REGULAR.value)
1020
+ video_process_menu.add_command(label="Cross-fade videos", compound="left", image=self.menu_icons["crossfade"]["img"], command=CrossfadeVideosPopUp, font=Formats.FONT_REGULAR.value)
1021
+ video_process_menu.add_command(label="Create average frames from videos", compound="left", image=self.menu_icons["average"]["img"], command=CreateAverageFramePopUp, font=Formats.FONT_REGULAR.value)
1022
+ video_process_menu.add_command(label="Validate video seekability", compound="left", image=self.menu_icons["search"]["img"], command=CheckVideoSeekablePopUp, font=Formats.FONT_REGULAR.value)
1023
+ video_process_menu.add_command(label="Visualize pose-estimation in folder...", compound="left", image=self.menu_icons["visualize"]["img"], command=VisualizePoseInFolderPopUp, font=Formats.FONT_REGULAR.value)
1024
+
1025
+ help_menu = Menu(menu)
1026
+ menu.add_cascade(label="Help", menu=help_menu)
1027
+ links_menu = Menu(help_menu)
1028
+ download_menu = Menu(links_menu)
1029
+ download_menu.add_command(label="Download weights", compound="left", image=self.menu_icons["dumbbell"]["img"], command=lambda: webbrowser.open_new(str(r"https://osf.io/sr3ck/")), font=Formats.FONT_REGULAR.value)
1030
+ download_menu.add_command(label="Download data/classifiers", compound="left", image=self.menu_icons["osf"]["img"], command=lambda: webbrowser.open_new(str(r"https://osf.io/kwge8/")), font=Formats.FONT_REGULAR.value)
1031
+
1032
+ yolo_links = Menu(download_menu)
1033
+ for mdl_name, mdl_link in Links.YOLO_11_WEIGHTS.value.items():
1034
+ yolo_links.add_command(label=mdl_name, compound="left", image=self.menu_icons["ultralytics_2"]["img"], command=lambda: webbrowser.open_new(str({mdl_link})), font=Formats.FONT_REGULAR.value)
1035
+
1036
+ download_menu.add_cascade(label="YOLO weights...", compound="left", image=self.menu_icons["ultralytics_2"]["img"], menu=yolo_links, font=Formats.FONT_REGULAR.value)
1037
+ links_menu.add_cascade(label="Download...", compound="left", image=self.menu_icons["download"]["img"], menu=download_menu, font=Formats.FONT_REGULAR.value)
1038
+ links_menu.add_command(label="SimBA Github", compound="left", image=self.menu_icons["github"]["img"], command=lambda: webbrowser.open_new(str(r"https://github.com/sgoldenlab/simba")), font=Formats.FONT_REGULAR.value)
1039
+ links_menu.add_command(label="SimBA Gitter Support Chatroom", compound="left", image=self.menu_icons["gitter"]["img"], command=lambda: webbrowser.open_new(str(r"https://gitter.im/SimBA-Resource/community")), font=Formats.FONT_REGULAR.value)
1040
+ links_menu.add_command(label="Install FFmpeg", compound="left", image=self.menu_icons["ffmpeg"]["img"], command=lambda: webbrowser.open_new(str(r"https://m.wikihow.com/Install-FFmpeg-on-Windows")), font=Formats.FONT_REGULAR.value)
1041
+ links_menu.add_command(label="SimBA API", compound="left", image=self.menu_icons["api"]["img"], command=lambda: webbrowser.open_new(str(r"https://simba-uw-tf-dev.readthedocs.io/")), font=Formats.FONT_REGULAR.value)
1042
+ links_menu.add_command(label="SimBA usage statistics", compound="left", image=self.menu_icons["line_chart_light_blue"]["img"], command=lambda: webbrowser.open_new(str(r"https://sronilsson.github.io/download_stats/")), font=Formats.FONT_REGULAR.value)
1043
+ links_menu.add_command(label="SimBA developer contact", compound="left", image=self.menu_icons["developer"]["img"], command=lambda: webbrowser.open_new(str(r"https://sronilsson.netlify.app/")), font=Formats.FONT_REGULAR.value)
1044
+
1045
+ help_menu.add_cascade(label="Links", menu=links_menu, compound="left", image=self.menu_icons["link"]["img"], font=Formats.FONT_REGULAR.value)
1046
+ help_menu.add_command(label="Check for updates", compound="left", image=self.menu_icons["download"]["img"], command=check_for_updates, font=Formats.FONT_REGULAR.value)
1047
+ help_menu.add_command(label="About", compound="left", image=self.menu_icons["about"]["img"], command=AboutSimBAPopUp, font=Formats.FONT_REGULAR.value)
1048
+
1049
+ self.frame = Frame(background, bd=2, relief=SUNKEN, width=750, height=300)
1050
+ self.r_click_menu = Menu(self.root, tearoff=0)
1051
+ self.r_click_menu.add_command(label="Copy selection", command=lambda: self.copy_selection_to_clipboard(), font=Formats.FONT_REGULAR.value)
1052
+ self.r_click_menu.add_command(label="Copy all", command=lambda: self.copy_all_to_clipboard(), font=Formats.FONT_REGULAR.value)
1053
+ self.r_click_menu.add_command(label="Paste", command=lambda: self.paste_to_txt(), font=Formats.FONT_REGULAR.value)
1054
+ self.r_click_menu.add_separator()
1055
+ self.r_click_menu.add_command(label="Clear", command=lambda: self.clean_txt(), font=Formats.FONT_REGULAR.value)
1056
+ y_sb = Scrollbar(self.frame, orient=VERTICAL)
1057
+ self.frame.pack(expand=True)
1058
+ self.txt = Text(self.frame, bg="white", insertborderwidth=2, height=30, width=100, yscrollcommand=y_sb)
1059
+ if currentPlatform == OS.WINDOWS.value: self.txt.bind("<Button-3>", self.show_right_click_pop_up)
1060
+ elif currentPlatform == OS.MAC.value: self.txt.bind("<Button-2>", self.show_right_click_pop_up)
1061
+ self.txt.tag_configure(TagNames.GREETING.value, justify="center", foreground="blue", font=Formats.FONT_LARGE_BOLD.value)
1062
+ self.txt.tag_configure(TagNames.ERROR.value, justify="left", foreground="red", font=Formats.FONT_REGULAR.value)
1063
+ self.txt.tag_configure(TagNames.STANDARD.value, justify="left", foreground="black", font=Formats.FONT_REGULAR.value)
1064
+ self.txt.tag_configure(TagNames.COMPLETE.value, justify="left", foreground="darkgreen", font=Formats.FONT_REGULAR_BOLD.value)
1065
+ self.txt.tag_configure(TagNames.WARNING.value, justify="left", foreground="darkorange", font=Formats.FONT_REGULAR.value)
1066
+ self.txt.tag_configure(TagNames.INFORMATION.value, justify="left", foreground="blue", font=Formats.FONT_REGULAR.value)
1067
+ self.txt.tag_configure("TABLE", foreground="darkorange", font=Formats.FONT_REGULAR.value, wrap="none", borderwidth=0)
1068
+ if ENV[ENV_VARS.PRINT_EMOJIS.value]:
1069
+ self.txt.insert(INSERT, Defaults.WELCOME_MSG.value + emojis["relaxed"] + "\n" * 2)
1070
+ else:
1071
+ self.txt.insert(INSERT, Defaults.WELCOME_MSG.value + "\n" * 2)
1072
+ self.txt.tag_add(TagNames.GREETING.value, "1.0", "3.25")
1073
+ y_sb.pack(side=RIGHT, fill=Y)
1074
+ self.txt.pack(expand=True, fill="both")
1075
+ y_sb.config(command=self.txt.yview)
1076
+ self.txt.config(state=DISABLED, font=Formats.FONT_REGULAR.value)
1077
+
1078
+ clear_txt_btn = SimbaButton(parent=self.frame, txt=" CLEAR", txt_clr='blue', img='clean', cmd=self.clean_txt, font=Formats.FONT_HEADER.value, anchor='center', hover_font=Formats.FONT_HEADER.value)
1079
+ clear_txt_btn.pack(side=BOTTOM, fill=X)
1080
+ sys.stdout = StdRedirector(self.txt)
1081
+
1082
+ if OS.PYTHON_VER.value != "3.6":
1083
+ self.txt['width'], self.txt['height'] = 200, 38
1084
+ PythonVersionWarning(msg=f"SimBA is not extensively tested beyond python 3.6. You are using python {OS.PYTHON_VER.value}. If you encounter errors in python>3.6, please report them on GitHub or Gitter (links in the help toolbar) and we will work together to fix the issues!", source=self.__class__.__name__)
1085
+
1086
+ if not check_ffmpeg_available():
1087
+ FFMpegNotFoundWarning(msg='SimBA could not find a FFMPEG installation on computer (as evaluated by "ffmpeg" returning None). SimBA works best with FFMPEG and it is recommended to install it on your computer', source=self.__class__.__name__)
1088
+
1089
+
1090
+
1091
+
1092
+ simba_pip_data = fetch_pip_data(pip_url=Links.SIMBA_PIP_URL.value)
1093
+ if (simba_pip_data[1] is not None) and OS.SIMBA_VERSION.value is not None:
1094
+ if simba_pip_data[1] != OS.SIMBA_VERSION.value:
1095
+ msg = f"A new version of SimBA is available: {simba_pip_data[1]} (you have version {OS.SIMBA_VERSION.value}). Consider upgrading using: pip install simba-uw-tf-dev --upgrade"
1096
+ VersionWarning(msg=msg)
1097
+
1098
+ def clear_recent_projects(self):
1099
+ file_path = os.path.join(os.path.dirname(__file__), Paths.RECENT_PROJECTS_PATHS.value)
1100
+ remove_files(file_paths=[file_path], raise_error=False)
1101
+ self.recent_projects_menu.delete(0, self.recent_projects_menu.index('end') - 1)
1102
+ self.file_menu.entryconfig("Open recent project...", state=DISABLED)
1103
+
1104
+
1105
+
1106
+ def restart(self):
1107
+ confirm_restart = askyesno(title="RESTART", message="Are you sure that you want restart SimBA?")
1108
+ if confirm_restart:
1109
+ self.root.destroy()
1110
+ os.execl(sys.executable, sys.executable, *sys.argv)
1111
+
1112
+ def clean_txt(self):
1113
+ self.txt.config(state=NORMAL)
1114
+ self.txt.delete("1.0", END)
1115
+
1116
+ def show_right_click_pop_up(self, event):
1117
+ try:
1118
+ self.r_click_menu.tk_popup(event.x_root, event.y_root)
1119
+ finally:
1120
+ self.r_click_menu.grab_release()
1121
+
1122
+ def copy_selection_to_clipboard(self):
1123
+ self.root.clipboard_clear()
1124
+ text = self.txt.get("sel.first", "sel.last")
1125
+ text = text.encode("ascii", "ignore").decode()
1126
+ self.root.clipboard_append(text)
1127
+
1128
+ def copy_all_to_clipboard(self):
1129
+ self.root.clipboard_clear()
1130
+ self.root.clipboard_append(self.txt.get("1.0", "end-1c"))
1131
+
1132
+ def paste_to_txt(self):
1133
+ try:
1134
+ print(self.root.clipboard_get())
1135
+ except UnicodeDecodeError:
1136
+ raise InvalidInputError(
1137
+ msg="Can only paste utf-8 compatible text",
1138
+ source=self.__class__.__name__,
1139
+ )
1140
+
1141
+
1142
+ class StdRedirector(object):
1143
+ def __init__(self, text_widget):
1144
+ self.text_space = text_widget
1145
+ self.emojis = get_emojis()
1146
+
1147
+ def write(self, s: str):
1148
+ tag_name = TagNames.STANDARD.value
1149
+ try:
1150
+ s, tag_name = s.split(Defaults.STR_SPLIT_DELIMITER.value, 2)
1151
+ except ValueError:
1152
+ pass
1153
+ if (tag_name != TagNames.STANDARD.value) and (tag_name != "TABLE"):
1154
+ if ENV[ENV_VARS.PRINT_EMOJIS.value]:
1155
+ s = s + " " + self.emojis[tag_name]
1156
+ else:
1157
+ pass
1158
+ self.text_space.config(state=NORMAL)
1159
+ self.text_space.insert("end", s, (tag_name))
1160
+ self.text_space.update()
1161
+ self.text_space.see("end")
1162
+ self.text_space.config(state=DISABLED)
1163
+
1164
+ def flush(self):
1165
+ pass
1166
+
1167
+ def terminate_children(children):
1168
+ for process in children:
1169
+ process.terminate()
1170
+
1171
+ def main():
1172
+ if currentPlatform == OS.WINDOWS.value:
1173
+ import ctypes
1174
+ myappid = "SimBA development wheel"
1175
+ ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
1176
+ SplashMovie()
1177
+ app = App()
1178
+ app.root.mainloop()