AmadeusGPT Demo: MABe dataset#

  • please get an openAI user key: https://platform.openai.com/api-keys.

  • We suggest to run the demos locally, but it can be viewed on Google Colab. Some interactive features might not be available.

!pip install --pre amadeusgpt
  • Let’s test that your open AI API Key works:

mykey = "paste-your-key-here"
from openai import OpenAI

client = OpenAI(api_key=mykey)

response = client.chat.completions.create(
    model="gpt-4",
    messages=[{"role": "user", "content": "Hello"}]
)
print(response.choices[0].message.content)
Hello! How can I assist you today?
import os
if 'OPENAI_API_KEY' not in os.environ:
     os.environ['OPENAI_API_KEY'] = mykey
from amadeusgpt import AMADEUS
from amadeusgpt.config import Config
import amadeusgpt
from amadeusgpt.utils import parse_result
from pathlib import Path
import matplotlib.pyplot as plt
from amadeusgpt import create_project

Please upload the demo video and associated files:#

amadeus_root = Path(amadeusgpt.__file__).parent.parent

kwargs = {
    "keypoint_info.body_orientation_keypoints.neck" : "nose",
    "keypoint_info.body_orientation_keypoints.tail_base" : "tail base",
    "keypoint_info.body_orientation_keypoints.animal_center" : "neck",
    "keypoint_info.head_orientation_keypoints.nose" : "nose",
    "keypoint_info.head_orientation_keypoints.neck" : "neck",
    "video_info.scene_frame_number" : 1400,
}

config = create_project(data_folder = "../examples/MABe", # check the path to the data folder
                        result_folder = "results",
                        **kwargs
                        )

amadeus = AMADEUS(config, use_vlm=True)
video_file_paths = amadeus.get_video_file_paths()
print (video_file_paths)
Project created at results. Results will be saved to results
The project will load video files (*.mp4) and optionally keypoint files from ../examples/MABe
A copy of the project config file is saved at results/config.yaml
{'data_info': {'data_folder': '../examples/MABe',
               'result_folder': 'results',
               'video_suffix': '.mp4'},
 'keypoint_info': {'body_orientation_keypoints': {'animal_center': 'neck',
                                                  'neck': 'nose',
                                                  'tail_base': 'tail base'},
                   'head_orientation_keypoints': {'neck': 'neck',
                                                  'nose': 'nose'},
                   'include_confidence': False,
                   'use_3d': False},
 'llm_info': {'gpt_model': 'gpt-4o',
              'keep_last_n_messages': 2,
              'max_tokens': 4096,
              'temperature': 0.0},
 'object_info': {'load_objects_from_disk': False, 'use_grid_objects': False},
 'video_info': {'scene_frame_number': 1400}}
INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions "HTTP/1.1 200 OK"
current total cost 0.003 $
current input tokens 438
current accumulated tokens 495
description of the image frame provided
```json
{
    "description": "The image shows a top view of three mice in a square enclosure with bedding.",
    "individuals": 3,
    "species": "topview_mouse",
    "background_objects": ["bedding", "enclosure"]
}
```
['../examples/MABe/EGS8X2MN4SSUGFWAV976.mp4']
behavior_analysis = amadeus.get_behavior_analysis(video_file_path='../examples/MABe/EGS8X2MN4SSUGFWAV976.mp4', # check the path to the video file
                                                  keypoint_file_path='../examples/MABe/EGS8X2MN4SSUGFWAV976.h5') # check the path to the keypoint file
scene_image = behavior_analysis.visual_manager.get_scene_image()
plt.imshow(scene_image)
<matplotlib.image.AxesImage at 0x31d92bd10>
../_images/97384d8e3a3c980c4e6159f73fa796621b3f70deef470684ceb6aabaa883f2e6.png
query = "Define watch as a social behavior where distance between animals is less than 260  \
and larger than 50 and head angle between animals is less than 15. The smooth_window_size is 15. Get watching"
qa_message = amadeus.step(query)
qa_message = parse_result(amadeus, qa_message)
INFO:httpx:HTTP Request: POST https://api.openai.com/v1/embeddings "HTTP/1.1 200 OK"
INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions "HTTP/1.1 200 OK"
current total cost 0.0224 $
current input tokens 2747
current accumulated tokens 3616

To accurately capture the “watching” behavior as defined, we need to use the get_animals_animals_events function from the AnimalBehaviorAnalysis class. This function allows us to specify conditions involving multiple animals, such as distance and relative head angle.

The conditions for the “watching” behavior are:

  • Distance between animals is less than 260 and larger than 50.

  • Relative head angle between animals is less than 15 degrees.

We will use these conditions in the cross_animal_query_list parameter of the get_animals_animals_events function. Additionally, we will set the smooth_window_size to 15 as specified.

Here is the code to achieve this:

def get_watching_events(identifier):
    '''
    Parameters:
    ----------
    identifier: Identifier. Contains information about the video, keypoint and config
    
    Returns:
    -------
    List[Event]: A list of events where the defined "watching" behavior occurs.
    '''
    # create_analysis returns an instance of AnimalBehaviorAnalysis
    analysis = create_analysis(identifier)
    
    # Define the conditions for the "watching" behavior
    cross_animal_query_list = [
        'distance<260',
        'distance>50',
        'relative_head_angle<15'
    ]
    
    # Capture the watching events using the specified conditions
    watching_events = analysis.get_animals_animals_events(
        cross_animal_query_list=cross_animal_query_list,
        bodypart_names=None,
        otheranimal_bodypart_names=None,
        min_window=11,
        max_window=100000,
        smooth_window_size=15
    )
    
    return watching_events

This function will return a list of events where the “watching” behavior, as defined by the specified conditions, occurs.

videos generated to defaultdict(<class 'list'>, {<amadeusgpt.behavior_analysis.identifier.Identifier object at 0x31dd3a3c0>: ['results/EGS8X2MN4SSUGFWAV976_get_watching_events_video_0.mp4', 'results/EGS8X2MN4SSUGFWAV976_get_watching_events_video_1.mp4', 'results/EGS8X2MN4SSUGFWAV976_get_watching_events_video_2.mp4', 'results/EGS8X2MN4SSUGFWAV976_get_watching_events_video_3.mp4']})
Open it with media player if it does not properly display in the notebook

[<amadeusgpt.analysis_objects.event.Event object at 0x31d891a00>, <amadeusgpt.analysis_objects.event.Event object at 0x31d890aa0>, <amadeusgpt.analysis_objects.event.Event object at 0x31d890110>, <amadeusgpt.analysis_objects.event.Event object at 0x31d890b60>]

[<amadeusgpt.analysis_objects.event.Event object at 0x31d891a00>, <amadeusgpt.analysis_objects.event.Event object at 0x31d890aa0>, <amadeusgpt.analysis_objects.event.Event object at 0x31d890110>, <amadeusgpt.analysis_objects.event.Event object at 0x31d890b60>]

[<amadeusgpt.analysis_objects.event.Event object at 0x31d891a00>, <amadeusgpt.analysis_objects.event.Event object at 0x31d890aa0>, <amadeusgpt.analysis_objects.event.Event object at 0x31d890110>, <amadeusgpt.analysis_objects.event.Event object at 0x31d890b60>]

[<amadeusgpt.analysis_objects.event.Event object at 0x31d891a00>, <amadeusgpt.analysis_objects.event.Event object at 0x31d890aa0>, <amadeusgpt.analysis_objects.event.Event object at 0x31d890110>, <amadeusgpt.analysis_objects.event.Event object at 0x31d890b60>]

../_images/9a5cbf007f18206b1866d9f5c466a199ad43b32cf68026da37b90fa285d8610b.png ../_images/e91a72502413709dbff03e5c8763b2fe1274fdf15a2b1d1181b0a88e703189fa.png

You can get a list of binary masks (equivalent to ethogram) for the underlying behavior, if your query is about retriving a described behavior#

# the return masks is of shape (num_of_events, video_length)
# where each boolean array of (video_length,) is binary where True indicates whether the behavior is happening at that frame
masks = qa_message.get_masks()
print (masks)
{<amadeusgpt.behavior_analysis.identifier.Identifier object at 0x31d93c8f0>: array([[False, False, False, ..., False, False, False],
       [False, False, False, ..., False, False, False],
       [False, False, False, ..., False, False, False],
       [False, False, False, ..., False, False, False]])}