Skip to content

Commit

Permalink
roi_nb
Browse files Browse the repository at this point in the history
  • Loading branch information
sronilsson committed Jan 18, 2025
1 parent 0e483e8 commit 388ea40
Show file tree
Hide file tree
Showing 9 changed files with 286 additions and 105 deletions.
152 changes: 152 additions & 0 deletions docs/nb/define_rois.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "e741f10a",
"metadata": {},
"outputs": [],
"source": [
"from simba.utils.read_write import find_files_of_filetypes_in_directory\n",
"from simba.utils.enums import Options\n",
"from simba.roi_tools.ROI_define import ROI_definitions\n",
"from simba.roi_tools.ROI_multiply import multiply_ROIs"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "cd6d77d7",
"metadata": {},
"outputs": [],
"source": [
"# DEFINE THE PATH TO THE SIMBA PROJECT CONFIG, AND THE PATH TO THE DIRECTORY IN SIMBA WHERE THE VIDEOS ARE STORED.\n",
"PROJECT_CONFIG_PATH = r\"C:\\troubleshooting\\mitra\\project_folder\\project_config.ini\"\n",
"VIDEO_DIR_PATH = r'C:\\troubleshooting\\mitra\\project_folder\\videos'"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "6efef9a3",
"metadata": {},
"outputs": [],
"source": [
"#CREATE A LIST OF PATHS TO THE VIDEO FILES THAT EXIST IN THE SIMBA PROJECT\n",
"video_file_paths = find_files_of_filetypes_in_directory(directory=VIDEO_DIR_PATH, extensions=Options.ALL_VIDEO_FORMAT_OPTIONS.value)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "c9d03e3c",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['C:\\\\troubleshooting\\\\mitra\\\\project_folder\\\\videos\\\\501_MA142_Gi_CNO_0514.mp4', 'C:\\\\troubleshooting\\\\mitra\\\\project_folder\\\\videos\\\\501_MA142_Gi_CNO_0516.mp4', 'C:\\\\troubleshooting\\\\mitra\\\\project_folder\\\\videos\\\\501_MA142_Gi_CNO_0521.mp4', 'C:\\\\troubleshooting\\\\mitra\\\\project_folder\\\\videos\\\\501_MA142_Gi_DCZ_0603.mp4', 'C:\\\\troubleshooting\\\\mitra\\\\project_folder\\\\videos\\\\501_MA142_Gi_Saline_0513.mp4']\n"
]
}
],
"source": [
"#WE CAN PRINT IT OUT THE FIRST 5 VIDEO PATHS IN THIS LIST TO SEE HOW IT LOOKS.\n",
"print(video_file_paths[:5])"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "aa4ad831",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"C:\\Users\\sroni\\.conda\\envs\\simba\\lib\\_collections_abc.py:666: MatplotlibDeprecationWarning:\n",
"\n",
"The global colormaps dictionary is no longer considered public API.\n",
"\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"SIMBA COMPLETE: ROI definitions saved for video: 501_MA142_Gi_CNO_0514 \tcomplete\n"
]
}
],
"source": [
"# WE RUN THE ROI DRAWING INTERFACE AND DRAW ROIs ON THE FIRST VIDEO IN THE LIST.\n",
"# ONCE THE ROIs ARE DRAWN ON THIS VIDEO, REMEMBER TO CLICK \"SAVE ROI DATA\", AND THEN CLOSE ALL OPEN THE INTERFACE WINDOWS.\n",
"_ = ROI_definitions(config_path=PROJECT_CONFIG_PATH, video_path=video_file_paths[0])"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "bc51d1d4",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"SIMBA COMPLETE: ROIs for 501_MA142_Gi_CNO_0514 applied to a further 99 videos (Duplicated rectangles count: 1, circles: 0, polygons: 0). \tcomplete\n",
"\n",
"Next, click on \"draw\" to modify ROI location(s) or click on \"reset\" to remove ROI drawing(s)\n"
]
}
],
"source": [
"#NEXT, WE MULTIPLY ALL THE ROIs ON THE FIRST VIDEO ON THE LIST ON ALL OTHE VIDEOS IN THE SIMBA PROJECT (THIS PROJECT CONTAINS A TOTAL OF 100 VIDEOS)\n",
"multiply_ROIs(config_path=PROJECT_CONFIG_PATH, filename=video_file_paths[0])"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "a065f176",
"metadata": {},
"outputs": [],
"source": [
"#FINALLY, WE START TO ITERATE OVER ALL OTHER VIDEOS IN THE PROJECT (OMITTING THE FIRST VIDEO), AND CORRECT THE ROIs.\n",
"# I DON'T HAVE A GOOD WAY OF AUTMATICALLY OPENING THE NEXT VIDEO ONCE A VIDEO IS CLOSED AT THE MOMENT, \n",
"# SO WILL HAVE TO MANUALLY CHANGE `video_file_paths[1]` TO `video_file_paths[2]` etc.\n",
"_ = ROI_definitions(config_path=PROJECT_CONFIG_PATH, video_path=video_file_paths[1])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8b2a1d89",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.13"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
1 change: 1 addition & 0 deletions docs/notebooks.rst
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ Miscellaneous

nb/import_sleap_h5
nb/multiclass
nb/define_rois



Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
# Setup configuration
setuptools.setup(
name="simba-uw-tf-dev",
version="2.5.2",
version="2.5.4",
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
11 changes: 5 additions & 6 deletions simba/data_processors/cuda/statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -532,17 +532,16 @@ def dunn_index(x: np.ndarray, y: np.ndarray) -> float:
.. seelalso:
For CPU-based method, use :func:`simba.mixins.statistics_mixin.Statistics.dunn_index`
.. math::
The Dunn Index is given by:
Dunn\ Index = \frac{\\min_{i \\neq j} \\delta(c_i, c_j)}{\\max_k \\Delta(c_k)}
.. math::
D = \frac{\min_{i \neq j} \{ \delta(C_i, C_j) \}}{\max_k \{ \Delta(C_k) \}}
Where:
- :math:`\\delta(c_i, c_j)` is the distance between clusters :math:`c_i` and :math:`c_j`.
- :math:`\\Delta(c_k)` is the diameter (i.e., maximum intra-cluster distance) of cluster :math:`c_k`.
where :math:`\delta(C_i, C_j)` is the distance between clusters :math:`C_i` and :math:`C_j`, and
:math:`\Delta(C_k)` is the diameter of cluster :math:`C_k`.
The higher the Dunn Index, the better the clustering, as a higher value indicates that the clusters are well-separated relative to their internal cohesion.
.. csv-table::
:header: EXPECTED RUNTIMES
:file: ../../../docs/tables/dunn_index_cuda.csv
Expand Down
5 changes: 4 additions & 1 deletion simba/mixins/feature_extraction_supplement_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -750,13 +750,16 @@ def distance_and_velocity(x: np.ndarray,
:param x: Array containing movement data. For example, created by ``simba.mixins.FeatureExtractionMixin.framewise_euclidean_distance``. If its a 2-dimensional array, then we assume its pixel coordinates. If it's a 1d array, we assume its frame-wise euclidean distances.
:param fps: Frames per second of the data.
:param pixels_per_mm: Conversion factor from pixels to millimeters.
:param Optional[bool] centimeters: If True, results are returned in centimeters and centimeters per second. Defaults to True.
:param Optional[bool] centimeters: If True, results are returned in centimeters and centimeters per second. Defaults to True. If false, then milimeters and millimeters per second.
:return: A tuple containing total movement and mean velocity.
:rtype: Tuple[float, float]
:example:
>>> x = np.random.randint(0, 100, (100,))
>>> sum_movement, avg_velocity = FeatureExtractionSupplemental.distance_and_velocity(x=x, fps=10, pixels_per_mm=10, centimeters=True)
>>> x = np.random.randint(0, 100, (100, 2))
>>> sum_movement, avg_velocity = FeatureExtractionSupplemental.distance_and_velocity(x=x, fps=10, pixels_per_mm=10, centimeters=True)
"""

check_valid_array(data=x, source=FeatureExtractionSupplemental.distance_and_velocity.__name__, accepted_ndims=(1, 2), accepted_dtypes=Formats.NUMERIC_DTYPES.value)
Expand Down
22 changes: 19 additions & 3 deletions simba/mixins/statistics_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3756,7 +3756,7 @@ def dunn_index(x: np.ndarray, y: np.ndarray, sample: Optional[float] = None) ->
The Dunn Index is given by:
.. math::
D = \\frac{\min_{i \neq j} \{ \delta(C_i, C_j) \}}{\max_k \{ \Delta(C_k) \}}
D = \frac{\min_{i \neq j} \{ \delta(C_i, C_j) \}}{\max_k \{ \Delta(C_k) \}}
where :math:`\delta(C_i, C_j)` is the distance between clusters :math:`C_i` and :math:`C_j`, and
:math:`\Delta(C_k)` is the diameter of cluster :math:`C_k`.
Expand Down Expand Up @@ -3983,8 +3983,13 @@ def xie_beni(x: np.ndarray, y: np.ndarray) -> float:
A lower Xie-Beni index indicates better clustering quality, signifying well-separated and compact clusters.
.. seealso::
To compute Xie-Beni on the GPU, use :func:`~simba.mixins.statistics_mixin.Statistics.xie_beni`
To compute Xie-Beni on the GPU, use :func:`~simba.mixins.statistics_mixin.Statistics.xie_beni`.
Significant GPU savings detected at about 1m features, 25 clusters
.. math::
\\text{XB} = \\frac{\\frac{1}{n} \\sum_{i=1}^{n} \\| x_i - c_{y_i} \\|^2}{\\min_{i \\neq j} \\| c_i - c_j \\|^2}
where :math:`n` is the total number of points in the dataset, :math:`x_i` is the :math:`i`-th data point, :math:`c_{y_i}` is the centroid of the cluster to which :math:`x_i` belongs, and :math:`\\| \\cdot \\|` denotes the Euclidean norm.
:param np.ndarray x: The dataset as a 2D NumPy array of shape (n_samples, n_features).
:param np.ndarray y: Cluster labels for each data point as a 1D NumPy array of shape (n_samples,).
Expand Down Expand Up @@ -4864,7 +4869,6 @@ def kumar_hassebrook_similarity(self, x: np.ndarray, y: np.ndarray) -> float:

def wave_hedges_distance(self, x: np.ndarray, y: np.ndarray) -> float:
"""
Computes the Wave-Hedges distance between two 1-dimensional arrays `x` and `y`. The Wave-Hedges distance is a measure of dissimilarity between arrays.
.. note::
Expand All @@ -4879,6 +4883,9 @@ def wave_hedges_distance(self, x: np.ndarray, y: np.ndarray) -> float:
>>> x = np.random.randint(0, 500, (1000,))
>>> y = np.random.randint(0, 500, (1000,))
>>> Statistics().wave_hedges_distance(x=x, y=y)
:references:
.. [1] Hedges, T. S. (1976). An empirical modification to linear wave theory. Proceedings of the Institution of Civil Engineers, Part 2, 61(3), 575–579. https://doi.org/10.1680/iicep.1976.3408
"""

check_valid_array(data=x, source=f'{Statistics.wave_hedges_distance.__name__} x', accepted_ndims=(1,), accepted_dtypes=Formats.NUMERIC_DTYPES.value)
Expand Down Expand Up @@ -4907,6 +4914,11 @@ def gower_distance(x: np.ndarray, y: np.ndarray) -> np.ndarray:
>>> x, y = np.random.randint(0, 500, (1000, 6000)), np.random.randint(0, 500, (1000, 6000))
>>> Statistics.gower_distance(x=x, y=y)
:references:
.. [1] Gower, J. C. (1971). A general coefficient of similarity and some of its properties. Biometrics, 27(4), 857–874. https://doi.org/10.2307/2528823
"""
check_valid_array(data=x, source=f'{Statistics.gower_distance.__name__} x', accepted_ndims=(1, 2), accepted_dtypes=Formats.NUMERIC_DTYPES.value)
check_valid_array(data=y, source=f'{Statistics.gower_distance.__name__} y', accepted_ndims=(x.ndim,), accepted_shapes=(x.shape,), accepted_dtypes=Formats.NUMERIC_DTYPES.value)
Expand Down Expand Up @@ -4952,6 +4964,10 @@ def normalized_google_distance(x: np.ndarray, y: np.ndarray) -> float:
:example:
>>> x, y = np.random.randint(0, 500, (1000,200)), np.random.randint(0, 500, (1000,200))
>>> Statistics.normalized_google_distance(x=y, y=x)
:references:
.. [1] Cilibrasi, R., & Vitányi, P. (2007). Clustering by compression. IEEE Transactions on Information Theory, 51(4), 1523-1545. https://doi.org/10.1109/TIT.2005.862080
"""
check_valid_array(data=x, source=f'{Statistics.normalized_google_distance.__name__} x', accepted_ndims=(1, 2), accepted_dtypes=Formats.NUMERIC_DTYPES.value)
check_valid_array(data=y, source=f'{Statistics.normalized_google_distance.__name__} y', accepted_ndims=(x.ndim,), accepted_shapes=(x.shape,), accepted_dtypes=Formats.NUMERIC_DTYPES.value)
Expand Down
23 changes: 13 additions & 10 deletions simba/roi_tools/ROI_define.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
from typing import Union
import copy
import os
from tkinter import *

import cv2
import pandas as pd
import warnings
warnings.simplefilter(action='ignore', category=pd.errors.PerformanceWarning)
import PIL.Image
from PIL import ImageTk

Expand Down Expand Up @@ -39,17 +42,17 @@ class ROI_definitions(ConfigReader, PopUpMixin):
video_path: str
path to video file for which ROIs should be defined.
Notes
----------
`ROI tutorials <https://github.com/sgoldenlab/simba/blob/master/docs/ROI_tutorial_new.md>`__.
.. note::
`ROI tutorials <https://github.com/sgoldenlab/simba/blob/master/docs/ROI_tutorial_new.md>`__.
Examples
----------
:example:
>>> _ = ROI_definitions(config_path='MyProjectConfig', video_path='MyVideoPath')
"""

def __init__(self, config_path: str, video_path: str):
def __init__(self,
config_path: Union[str, os.PathLike],
video_path: Union[str, os.PathLike]):

check_file_exist_and_readable(file_path=config_path)
check_file_exist_and_readable(file_path=video_path)
Expand All @@ -67,9 +70,6 @@ def __init__(self, config_path: str, video_path: str):

self.menu_icons = get_icons_paths()

for k in self.menu_icons.keys():
self.menu_icons[k]["img"] = ImageTk.PhotoImage(image=PIL.Image.open(os.path.join(os.path.dirname(__file__), self.menu_icons[k]["icon_path"])))

self.roi_root = Toplevel()
self.roi_root.minsize(WINDOW_SIZE[0], WINDOW_SIZE[1])
self.screen_width = self.roi_root.winfo_screenwidth()
Expand All @@ -79,6 +79,9 @@ def __init__(self, config_path: str, video_path: str):
self.roi_root.wm_title("Region of Interest Settings")
self.roi_root.protocol("WM_DELETE_WINDOW", self._terminate)

for k in self.menu_icons.keys():
self.menu_icons[k]["img"] = ImageTk.PhotoImage(image=PIL.Image.open(os.path.join(os.path.dirname(__file__), self.menu_icons[k]["icon_path"])))

self.shape_thickness_list = list(range(1, 26))
self.ear_tag_size_list = list(range(1, 26))
self.select_color = "red"
Expand Down Expand Up @@ -113,7 +116,7 @@ def __init__(self, config_path: str, video_path: str):
if len(self.video_ROIs) > 0:
self.update_delete_ROI_menu()

self.master.mainloop()
#self.master.mainloop()

def _terminate(self):
self.Exit()
Expand Down
Loading

0 comments on commit 388ea40

Please sign in to comment.