Skip to content

Commit

Permalink
boris project files
Browse files Browse the repository at this point in the history
  • Loading branch information
sronilsson committed Sep 18, 2024
1 parent 827b0cf commit f155298
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 36 deletions.
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
# Setup configuration
setuptools.setup(
name="Simba-UW-tf-dev",
version="2.1.6",
version="2.1.7",
author="Simon Nilsson, Jia Jie Choong, Sophia Hwang",
author_email="[email protected]",
description="Toolkit for computer classification and analysis of behaviors in experimental animals",
Expand Down
4 changes: 4 additions & 0 deletions simba/data_processors/cuda/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,10 @@ def stack_sliding_mse(x: np.ndarray,
For CPU function see :func:`~simba.mixins.image_mixin.ImageMixin.img_stack_mse` and
:func:`~simba.mixins.image_mixin.ImageMixin.img_sliding_mse`.
.. math::
\text{MSE} = \frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2
:param np.ndarray x: Input array of images, where the first dimension corresponds to the stack of images. The array should be either 3D (height, width, channels) or 4D (batch, height, width, channels).
:param Optional[int] stride: The stride or step size for the sliding window that determines the reference image. Defaults to 1, meaning the previous image in the stack is used as the reference.
:param Optional[int] batch_size: The number of images to process in a single batch. Larger batch sizes may improve performance but require more GPU memory. Defaults to 1000.
Expand Down
26 changes: 6 additions & 20 deletions simba/third_party_label_appenders/BORIS_appender.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ def run(self):
else:
video_annot = boris_annotation_dict[self.file_name]
data_df = read_df(file_path, self.file_type)
video_annot = video_annot.fillna(len(data_df))
print(video_annot)
for clf_name in self.clf_names:
data_df[clf_name] = 0
if clf_name not in video_annot[BEHAVIOR].unique():
Expand Down Expand Up @@ -101,23 +103,7 @@ def __save_boris_annotations(self, df):
# #test.create_boris_master_file()
# test.run()




# test = BorisAppender(config_path='/Users/simon/Desktop/envs/troubleshooting/two_black_animals_14bp/project_folder/project_config.ini',
# data_dir='/Users/simon/Downloads/FIXED')
# test.create_boris_master_file()
# test.run()

# test = BorisAppender(config_path='/Users/simon/Desktop/troubleshooting/train_model_project/project_folder/project_config.ini', boris_folder=r'/Users/simon/Desktop/troubleshooting/train_model_project/boris_import')
# test.create_boris_master_file()
# test.append_boris()

# test = BorisAppender(config_path='/Users/simon/Desktop/envs/marcel_boris/project_folder/project_config.ini', boris_folder=r'/Users/simon/Desktop/envs/marcel_boris/BORIS_data')
# test.create_boris_master_file()
# test.append_boris()

# test = BorisAppender(config_path='/Users/simon/Desktop/envs/troubleshooting/two_black_animals_14bp/project_folder/project_config.ini',
# boris_folder='/Users/simon/Downloads/FIXED')
# test.create_boris_master_file()
# test.append_boris()
#
# test = BorisAppender(config_path=r"C:\troubleshooting\two_black_animals_14bp\project_folder\project_config.ini",
# data_dir=r"C:\troubleshooting\two_black_animals_14bp\BORIS")
# test.run()
2 changes: 1 addition & 1 deletion simba/third_party_label_appenders/third_party_appender.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ def run(self):
# test.run()
#

#

# log = True
# file_format = 'xlsx'
# error_settings = {'INVALID annotations file data format': 'WARNING',
Expand Down
46 changes: 32 additions & 14 deletions simba/utils/read_write.py
Original file line number Diff line number Diff line change
Expand Up @@ -2239,14 +2239,12 @@ def _find_cap_insensitive_name(target: str, values: List[str]) -> Union[None, st
return None
else:
return values[values_lower.index(target_lower)]

def read_boris_file(file_path: Union[str, os.PathLike],
fps: Optional[Union[int, float]] = None,
orient: Optional[Literal['index', 'columns']] = 'index',
save_path: Optional[Union[str, os.PathLike]] = None,
raise_error: Optional[bool] = False,
log_setting: Optional[bool] = False) -> Union[None, Dict[str, Dict[str, pd.DataFrame]]]:

"""
Reads a BORIS behavioral annotation file, processes the data, and optionally saves the results to a file.
Expand All @@ -2270,6 +2268,7 @@ def read_boris_file(file_path: Union[str, os.PathLike],
FRAME = 'FRAME'
STOP = 'STOP'
STATUS = "Status"
FRAME_INDEX = 'Image index'
MEDIA_FILE_PATH = "Media file path"

check_file_exist_and_readable(file_path=file_path)
Expand All @@ -2283,16 +2282,20 @@ def read_boris_file(file_path: Union[str, os.PathLike],
expected_headers = [TIME, MEDIA_FILE_PATH, BEHAVIOR, STATUS]
if not OBSERVATION_ID in boris_df.columns:
if raise_error:
raise InvalidFileTypeError(msg=f'{file_path} is not a valid BORIS file', source=read_boris_file.__name__)
raise InvalidFileTypeError(msg=f'{file_path} is not a valid BORIS file',
source=read_boris_file.__name__)
else:
ThirdPartyAnnotationsInvalidFileFormatWarning(annotation_app="BORIS", file_path=file_path, source=read_boris_file.__name__, log_status=log_setting)
ThirdPartyAnnotationsInvalidFileFormatWarning(annotation_app="BORIS", file_path=file_path,
source=read_boris_file.__name__, log_status=log_setting)
return {}
start_idx = boris_df[boris_df[OBSERVATION_ID] == TIME].index.values
if len(start_idx) != 1:
if raise_error:
raise InvalidFileTypeError(msg=f'{file_path} is not a valid BORIS file', source=read_boris_file.__name__)
raise InvalidFileTypeError(msg=f'{file_path} is not a valid BORIS file',
source=read_boris_file.__name__)
else:
ThirdPartyAnnotationsInvalidFileFormatWarning(annotation_app="BORIS", file_path=file_path, source=read_boris_file.__name__, log_status=log_setting)
ThirdPartyAnnotationsInvalidFileFormatWarning(annotation_app="BORIS", file_path=file_path,
source=read_boris_file.__name__, log_status=log_setting)
return {}
df = pd.read_csv(file_path, skiprows=range(0, int(start_idx + 1)))
else:
Expand All @@ -2303,19 +2306,25 @@ def read_boris_file(file_path: Union[str, os.PathLike],
numeric_check = pd.to_numeric(df[TIME], errors='coerce').notnull().all()
if not numeric_check:
if raise_error:
raise InvalidInputError(msg=f'SimBA found TIME DATA annotation in file {file_path} that could not be interpreted as numeric values (seconds or frame numbers)')
raise InvalidInputError(
msg=f'SimBA found TIME DATA annotation in file {file_path} that could not be interpreted as numeric values (seconds or frame numbers)')
else:
ThirdPartyAnnotationsInvalidFileFormatWarning(annotation_app="BORIS", file_path=file_path, source=read_boris_file.__name__, log_status=log_setting)
return {}
df[TIME] = df[TIME].astype(np.float32)
media_file_names_in_file = df[MEDIA_FILE_PATH].unique()
FRAME_INDEX = _find_cap_insensitive_name(target=FRAME_INDEX, values=list(df.columns))
if fps is None:
FPS = _find_cap_insensitive_name(target=FPS, values=list(df.columns))
if not FPS in df.columns:
if raise_error:
raise FrameRangeError(f'The annotations are in seconds and FPS was not passed. FPS could also not be read from the BORIS file', source=read_boris_file.__name__)
raise FrameRangeError(
f'The annotations are in seconds and FPS was not passed. FPS could also not be read from the BORIS file',
source=read_boris_file.__name__)
else:
FrameRangeWarning(msg=f'The annotations are in seconds and FPS was not passed. FPS could also not be read from the BORIS file', source=read_boris_file.__name__)
FrameRangeWarning(
msg=f'The annotations are in seconds and FPS was not passed. FPS could also not be read from the BORIS file',
source=read_boris_file.__name__)
ThirdPartyAnnotationsInvalidFileFormatWarning(annotation_app="BORIS", file_path=file_path, source=read_boris_file.__name__, log_status=log_setting)
return {}
if len(media_file_names_in_file) == 1:
Expand All @@ -2328,28 +2337,37 @@ def read_boris_file(file_path: Union[str, os.PathLike],
for fps_value in fps_lst:
check_float(name='fps', value=fps_value, min_value=10e-6, raise_error=True)
fps.append(float(fps_value))
if FRAME_INDEX is not None:
expected_headers.append(FRAME_INDEX)
df = df[expected_headers]

results = {}
for video_cnt, video_file_name in enumerate(media_file_names_in_file):
video_name = get_fn_ext(filepath=video_file_name)[1]
results[video_name] = {}
video_fps = fps[video_cnt]
video_df = df[df[MEDIA_FILE_PATH] == video_file_name].reset_index(drop=True)
video_df['FRAME'] = (df[TIME] * video_fps).astype(int)
if FRAME_INDEX is None:
video_df['FRAME'] = (video_df[TIME] * video_fps).astype(int)
else:
video_df['FRAME'] = video_df[FRAME_INDEX]
video_df = video_df.drop([TIME, MEDIA_FILE_PATH], axis=1)
video_df = video_df.rename(columns={BEHAVIOR: 'BEHAVIOR', STATUS: EVENT})
for clf in video_df['BEHAVIOR'].unique():
video_clf_df = video_df[video_df['BEHAVIOR'] == clf].reset_index(drop=True)
if orient == 'index':
start_clf, stop_clf = video_clf_df[video_clf_df[EVENT] == START].reset_index(drop=True), video_clf_df[video_clf_df[EVENT] == STOP].reset_index(drop=True)
start_clf, stop_clf = video_clf_df[video_clf_df[EVENT] == START].reset_index(drop=True), video_clf_df[
video_clf_df[EVENT] == STOP].reset_index(drop=True)
start_clf = start_clf.rename(columns={FRAME: START}).drop([EVENT, 'BEHAVIOR'], axis=1)
stop_clf = stop_clf.rename(columns={FRAME: STOP}).drop([EVENT], axis=1)
if len(start_clf) != len(stop_clf):
if raise_error:
raise FrameRangeError(f'In file {file_path}, the number of start events ({len(start_clf)}) and stop events ({len(stop_clf)}) for behavior {clf} and video {video_name} is not equal', source=read_boris_file.__name__)
raise FrameRangeError(
f'In file {file_path}, the number of start events ({len(start_clf)}) and stop events ({len(stop_clf)}) for behavior {clf} and video {video_name} is not equal',
source=read_boris_file.__name__)
else:
FrameRangeWarning(msg=f'In file {file_path}, the number of start events ({len(start_clf)}) and stop events ({len(stop_clf)}) for behavior {clf} and video {video_name} is not equal', source=read_boris_file.__name__)
FrameRangeWarning(
msg=f'In file {file_path}, the number of start events ({len(start_clf)}) and stop events ({len(stop_clf)}) for behavior {clf} and video {video_name} is not equal',
source=read_boris_file.__name__)
return results
video_clf_df = pd.concat([start_clf, stop_clf], axis=1)[['BEHAVIOR', START, STOP]]
results[video_name][clf] = video_clf_df
Expand Down

0 comments on commit f155298

Please sign in to comment.