Skip to content

facial_behavior_estimation.py

activate(facemap_schema_name, *, create_schema=True, create_tables=True, linking_module=None)

Activate schema.

Parameters:

Name Type Description Default
facemap_schema_name str

Schema name on the database server to activate the facemap element

required
create_schema bool

When True (default), create schema in the database if it does not yet exist.

True
create_tables bool

When True (default), create tables in the database if they do not yet exist.

True
linking_module str

A module name or a module containing the required dependencies to activate the facial_behavior_estimation module:

None

Dependencies: Upstream tables: + Session: A parent table to VideoRecording, identifying a recording session + Equipment: A parent table to VideoRecording, identifying video recording equipment Functions: + get_facemap_root_data_dir() -> list Retrieves the root data directory(s) with face recordings for all subject/sessions. Returns a string for the full path to the root data directory. + get_facemap_processed_data_dir(session_key: dict) -> str Optional function to retrieve the desired output directory for Facemap files for a given session. If unspecified, the output is stored in the video folder for the session, which is the default behavior of Facemap. Returns a string of the absolute path of the output directory.

Source code in element_facemap/facial_behavior_estimation.py
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
def activate(
    facemap_schema_name, *, create_schema=True, create_tables=True, linking_module=None
):
    """Activate schema.

    Args:
        facemap_schema_name (str): Schema name on the database server to activate the
            `facemap` element
        create_schema (bool): When True (default), create schema in the database if it
            does not yet exist.
        create_tables (bool): When True (default), create tables in the database if
            they do not yet exist.
        linking_module (str): A module name or a module containing the required
            dependencies to activate the `facial_behavior_estimation` module:

    Dependencies:
    Upstream tables:
        + Session: A parent table to VideoRecording, identifying a recording session
        + Equipment: A parent table to VideoRecording, identifying video recording equipment
    Functions:
        + get_facemap_root_data_dir() -> list
            Retrieves the root data directory(s) with face recordings for all
            subject/sessions. Returns a string for the full path to the root data directory.
        + get_facemap_processed_data_dir(session_key: dict) -> str
            Optional function to retrieve the desired output directory
            for Facemap files for a given session. If unspecified,
            the output is stored in the video folder for the session, which is the default behavior of Facemap.
            Returns a string of the absolute path of the output directory.
    """
    if isinstance(linking_module, str):
        linking_module = importlib.import_module(linking_module)
    assert inspect.ismodule(
        linking_module
    ), "The argument 'dependency' must be a module's name or a module"
    assert hasattr(
        linking_module, "get_facemap_root_data_dir"
    ), "The linking module must specify a lookup function for a root data directory"

    global _linking_module
    _linking_module = linking_module

    # activate
    schema.activate(
        facemap_schema_name,
        create_schema=create_schema,
        create_tables=create_tables,
        add_objects=_linking_module.__dict__,
    )

get_facemap_root_data_dir()

Pull the relevant function from the parent namespace to specify the root data directory(s).

It is recommended that all paths in DataJoint Elements are stored as relative paths, with respect to some user-configured "root" directory. The root(s) may vary between data modalities and user machines.

Returns:

Name Type Description
paths list

list of path(s) to root data directory(s) for Facemap

Source code in element_facemap/facial_behavior_estimation.py
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
def get_facemap_root_data_dir():
    """Pull the relevant function from the parent namespace to specify the root data directory(s).

    It is recommended that all paths in DataJoint Elements are stored as relative
    paths, with respect to some user-configured "root" directory. The
    root(s) may vary between data modalities and user machines.

    Returns:
        paths (list): list of path(s) to root data directory(s) for Facemap
    """
    root_directories = _linking_module.get_facemap_root_data_dir()
    if isinstance(root_directories, (str, Path)):
        root_directories = [root_directories]

    if hasattr(_linking_module, "get_facemap_processed_data_dir"):
        root_directories.append(_linking_module.get_facemap_processed_data_dir())

    return root_directories

get_facemap_processed_data_dir()

Facemap output directory

If specified by the user, this function provides Facemap with an output directory for processed files. If unspecified, the output is stored in the video directory for the session, which is the default behavior of Facemap.

Returns:

Name Type Description
path str

path to Facemap output directory

Source code in element_facemap/facial_behavior_estimation.py
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
def get_facemap_processed_data_dir() -> str:
    """Facemap output directory

    If specified by the user, this function provides Facemap with an output
    directory for processed files. If unspecified, the output is stored in the video directory for the session, which is the default behavior of Facemap.

    Returns:
        path (str): path to Facemap output directory
    """
    if hasattr(_linking_module, "get_facemap_processed_data_dir"):
        return _linking_module.get_facemap_processed_data_dir()
    else:
        return get_facemap_root_data_dir()[0]

get_facemap_video_files(video_key)

Retrieve the list of video recording files.

Parameters:

Name Type Description Default
video_key dict

Primary key of an entry in the VideoRecording table.

required

Returns:

Type Description
List[Path]

List of absolute POSIX paths of the video files.

Source code in element_facemap/facial_behavior_estimation.py
106
107
108
109
110
111
112
113
114
115
def get_facemap_video_files(video_key: dict) -> List[Path]:
    """Retrieve the list of video recording files.

    Args:
        video_key: Primary key of an entry in the VideoRecording table.

    Returns:
        List of absolute POSIX paths of the video files.
    """
    return _linking_module.get_facemap_video_files(video_key)

VideoRecording

Bases: Manual

Video recorded in an experiment session for Facemap analysis.

Attributes:

Name Type Description
Session foreign key

Primary key from Session.

recording_id int

Recording ID.

Device foreign key

Primary key from Device.

Source code in element_facemap/facial_behavior_estimation.py
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
@schema
class VideoRecording(dj.Manual):
    """Video recorded in an experiment session for Facemap analysis.

    Attributes:
        Session (foreign key): Primary key from Session.
        recording_id (int): Recording ID.
        Device (foreign key): Primary key from Device.
    """

    definition = """
    -> Session
    recording_id                : int
    ---
    -> Device
    """

    # One VideoRecording can be saved in multiple files
    class File(dj.Part):
        """Relative path of video file with respect to facemap_root_data_dir directory.

        Attributes:
            master (foreign key): Primary key from VideoRecording.
            file_id (smallint): File ID.
            file_path (str): Filepath of video, relative to root directory.
        """

        definition = """
        -> master
        file_id     : smallint
        ---
        file_path   : varchar(255)  # filepath of video, relative to root directory
        """

File

Bases: Part

Relative path of video file with respect to facemap_root_data_dir directory.

Attributes:

Name Type Description
master foreign key

Primary key from VideoRecording.

file_id smallint

File ID.

file_path str

Filepath of video, relative to root directory.

Source code in element_facemap/facial_behavior_estimation.py
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
class File(dj.Part):
    """Relative path of video file with respect to facemap_root_data_dir directory.

    Attributes:
        master (foreign key): Primary key from VideoRecording.
        file_id (smallint): File ID.
        file_path (str): Filepath of video, relative to root directory.
    """

    definition = """
    -> master
    file_id     : smallint
    ---
    file_path   : varchar(255)  # filepath of video, relative to root directory
    """

RecordingInfo

Bases: Imported

Information extracted from video file.

Attributes:

Name Type Description
VideoRecording foreign key

Primary key for VideoRecording table.

px_height int

Height in pixels.

px_width int

Width in pixels.

nframes int

Number of frames.

fps int

Frames per second in Hz.

recording_duration float

Video duration in seconds.

recording_time datetime

Time at the beginning of the recording.

Source code in element_facemap/facial_behavior_estimation.py
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
@schema
class RecordingInfo(dj.Imported):
    """Information extracted from video file.

    Attributes:
        VideoRecording (foreign key): Primary key for VideoRecording table.
        px_height (int): Height in pixels.
        px_width (int): Width in pixels.
        nframes (int): Number of frames.
        fps (int): Frames per second in Hz.
        recording_duration (float): Video duration in seconds.
        recording_time (datetime, optional): Time at the beginning of the recording.
    """

    definition = """
    -> VideoRecording
    ---
    px_height             : int       # height in pixels
    px_width              : int       # width in pixels
    nframes               : int       # number of frames
    fps                   : int       # frames per second in Hz
    recording_duration    : float     # video duration in seconds
    recording_time = NULL : datetime  # time at the beginning of the recording
    """

    @property
    def key_source(self):
        """Limits the population of RecordingInfo to video recordings that have file paths ingested."""
        return VideoRecording & VideoRecording.File

    def make(self, key):
        """Populates the RecordingInfo table."""

        file_paths = (VideoRecording.File & key).fetch("file_path")

        nframes = 0
        px_height, px_width, fps = None, None, None

        for file_path in file_paths:
            file_path = (
                find_full_path(get_facemap_root_data_dir(), file_path)
            ).as_posix()

            cap = cv2.VideoCapture(file_path)
            info = (
                int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)),
                int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),
                int(cap.get(cv2.CAP_PROP_FPS)),
            )
            if px_height is not None:
                assert (px_height, px_width, fps) == info
            px_height, px_width, fps = info
            nframes += int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
            cap.release()

        self.insert1(
            {
                **key,
                "px_height": px_height,
                "px_width": px_width,
                "nframes": nframes,
                "fps": fps,  # usually user-defined and wrong
                "recording_duration": nframes / fps,  # see caution above
            }
        )

key_source property

Limits the population of RecordingInfo to video recordings that have file paths ingested.

make(key)

Populates the RecordingInfo table.

Source code in element_facemap/facial_behavior_estimation.py
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
def make(self, key):
    """Populates the RecordingInfo table."""

    file_paths = (VideoRecording.File & key).fetch("file_path")

    nframes = 0
    px_height, px_width, fps = None, None, None

    for file_path in file_paths:
        file_path = (
            find_full_path(get_facemap_root_data_dir(), file_path)
        ).as_posix()

        cap = cv2.VideoCapture(file_path)
        info = (
            int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)),
            int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),
            int(cap.get(cv2.CAP_PROP_FPS)),
        )
        if px_height is not None:
            assert (px_height, px_width, fps) == info
        px_height, px_width, fps = info
        nframes += int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
        cap.release()

    self.insert1(
        {
            **key,
            "px_height": px_height,
            "px_width": px_width,
            "nframes": nframes,
            "fps": fps,  # usually user-defined and wrong
            "recording_duration": nframes / fps,  # see caution above
        }
    )

FacemapTask

Bases: Manual

Staging table for pairing of recording and Facemap parameters before processing.

Attributes:

Name Type Description
VideoRecording foreign key

Primary key for VideoRecording table.

facemap_task_id smallint

Facemap task ID

facemap_output_dir str

output dir storing the results of Facemap analysis.

task_mode enum

Default load. Load or trigger analysis.

facemap_params longblob

content of facemap's _proc.npy as dict.

do_mot_svd bool

Default True. Do motion singular value decomposition.

do_mov_svd bool

Default False. Do movie singular value decomposition.

task_description str

Task description.

Source code in element_facemap/facial_behavior_estimation.py
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
@schema
class FacemapTask(dj.Manual):
    """Staging table for pairing of recording and Facemap parameters before processing.

    Attributes:
        VideoRecording (foreign key): Primary key for VideoRecording table.
        facemap_task_id (smallint): Facemap task ID
        facemap_output_dir (str, optional): output dir storing the results
            of Facemap analysis.
        task_mode (enum): Default load. Load or trigger analysis.
        facemap_params (longblob): content of facemap's _proc.npy as dict.
        do_mot_svd (bool): Default True. Do motion singular value decomposition.
        do_mov_svd (bool): Default False. Do movie singular value decomposition.
        task_description (str, optional): Task description.
    """

    definition = """
    # Staging table for pairing of recording and Facemap parameters before processing.
    -> VideoRecording
    facemap_task_id             : smallint
    ---
    facemap_output_dir=''       : varchar(255)  # output directory - storing the results of Facemap analysis
    task_mode='load'            : enum('load', 'trigger')
    facemap_params              : longblob  # content of facemap's _proc.npy as dict
    do_mot_svd=1                : bool
    do_mov_svd=0                : bool
    task_description=''         : varchar(128)
    """

    def infer_output_dir(self, key, relative=True, mkdir=True):
        video_file = (VideoRecording.File & key).fetch("file_path", limit=1)[0]
        video_dir = find_full_path(get_facemap_root_data_dir(), video_file).parent
        root_dir = find_root_directory(get_facemap_root_data_dir(), video_dir)

        paramset_key = (FacemapTask & key).fetch1("facemap_task_id")
        processed_dir = Path(get_facemap_processed_data_dir())
        output_dir = (
            processed_dir / video_dir.relative_to(root_dir) / f"facemap_{paramset_key}"
        )

        if mkdir:
            output_dir.mkdir(parents=True, exist_ok=True)

        return output_dir.relative_to(processed_dir) if relative else output_dir

FacemapProcessing

Bases: Computed

Automated table to run Facemap with inputs from FacemapTask.

Attributes:

Name Type Description
FacemapTask foreign key

Primary key from FacemapTask.

processing_time datetime

Time of generation of the facemap results.

package_version str

Facemap package version.

Source code in element_facemap/facial_behavior_estimation.py
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
@schema
class FacemapProcessing(dj.Computed):
    """Automated table to run Facemap with inputs from FacemapTask.

    Attributes:
        FacemapTask (foreign key): Primary key from FacemapTask.
        processing_time (datetime): Time of generation of the facemap results.
        package_version (str, optional): Facemap package version.
    """

    definition = """
    # Processing Procedure
    -> FacemapTask
    ---
    processing_time     : datetime  # time of generation of the facemap results
    package_version=''  : varchar(16)
    """

    # Process only the VideoRecordings that have their Info inserted.
    @property
    def key_source(self):
        """Limits the population of FacemapProcessing to those that have VideoRecording.File defined."""
        return FacemapTask & VideoRecording.File

    def make(self, key):
        """Runs Facemap"""

        task_mode = (FacemapTask & key).fetch1("task_mode")

        output_dir = (FacemapTask & key).fetch1("facemap_output_dir")
        if not output_dir:
            output_dir = FacemapTask().infer_output_dir(key, relative=True, mkdir=True)
            # update processing_output_dir
            FacemapTask.update1({**key, "facemap_output_dir": output_dir.as_posix()})

        if task_mode == "trigger":
            from facemap.process import run as facemap_run

            params = (FacemapTask & key).fetch1("facemap_params")

            video_files = (FacemapTask * VideoRecording.File & key).fetch("file_path")
            video_files = [
                [
                    find_full_path(get_facemap_root_data_dir(), video_file).as_posix()
                    for video_file in video_files
                ]
            ]

            output_dir = find_full_path(get_facemap_root_data_dir(), output_dir)
            facemap_run(
                video_files,
                sbin=params["sbin"],
                proc=params,
                savepath=output_dir.as_posix(),
                motSVD=params["motSVD"],
                movSVD=params["movSVD"],
            )

        _, creation_time = get_loader_result(key, FacemapTask)
        key = {**key, "processing_time": creation_time}

        self.insert1(key)

key_source property

Limits the population of FacemapProcessing to those that have VideoRecording.File defined.

make(key)

Runs Facemap

Source code in element_facemap/facial_behavior_estimation.py
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
def make(self, key):
    """Runs Facemap"""

    task_mode = (FacemapTask & key).fetch1("task_mode")

    output_dir = (FacemapTask & key).fetch1("facemap_output_dir")
    if not output_dir:
        output_dir = FacemapTask().infer_output_dir(key, relative=True, mkdir=True)
        # update processing_output_dir
        FacemapTask.update1({**key, "facemap_output_dir": output_dir.as_posix()})

    if task_mode == "trigger":
        from facemap.process import run as facemap_run

        params = (FacemapTask & key).fetch1("facemap_params")

        video_files = (FacemapTask * VideoRecording.File & key).fetch("file_path")
        video_files = [
            [
                find_full_path(get_facemap_root_data_dir(), video_file).as_posix()
                for video_file in video_files
            ]
        ]

        output_dir = find_full_path(get_facemap_root_data_dir(), output_dir)
        facemap_run(
            video_files,
            sbin=params["sbin"],
            proc=params,
            savepath=output_dir.as_posix(),
            motSVD=params["motSVD"],
            movSVD=params["movSVD"],
        )

    _, creation_time = get_loader_result(key, FacemapTask)
    key = {**key, "processing_time": creation_time}

    self.insert1(key)

FacialSignal

Bases: Imported

Results of the Facemap analysis.

Attributes:

Name Type Description
FacemapProcessing foreign key)

Primary key for FacemapProcessing table.

Source code in element_facemap/facial_behavior_estimation.py
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
@schema
class FacialSignal(dj.Imported):
    """Results of the Facemap analysis.

    Attributes:
        FacemapProcessing (foreign key) : Primary key for FacemapProcessing table.
    """

    definition = """# Facemap results
    -> FacemapProcessing
    """

    class Region(dj.Part):
        """Region's properties.

        Attributes:
            master (foreign key): Primary key of the FacialSignal table.
            roi_no (int): Region number.
            roi_name (str, optional): User-friendly name of the roi.
            xrange (longblob): 1d np.array - x pixel indices.
            yrange (longblob): 1d np.array - y pixel indices.
            xrange_bin (longblob): 1d np.array - binned x pixel indices.
            yrange_bin (longblob): 1d np.array - binned y pixel indices.
            motion (longblob): 1d np.array - absolute motion energies (nframes).
        """

        definition = """
        -> master
        roi_no        : int         # Region number
        ---
        roi_name=''   : varchar(16) # user-friendly name of the roi
        xrange        : longblob    # 1d np.array - x pixel indices
        yrange        : longblob    # 1d np.array - y pixel indices
        xrange_bin    : longblob    # 1d np.array - binned x pixel indices
        yrange_bin    : longblob    # 1d np.array - binned y pixel indices
        motion        : longblob    # 1d np.array - absolute motion energies (nframes)
        """

    class MotionSVD(dj.Part):
        """Components of the SVD from motion video.

        Attributes:
            master.Region (foreign key): Primary key from FacialSignal.Region.
            pc_no (int): Principle component (PC) number.
            singular_value (float, optional): singular value corresponding to the PC.
            motmask (longblob): PC (y, x).
            projection (longblob): projections onto the principle component (nframes).
        """

        definition = """
        -> master.Region
        pc_no               : int         # principle component (PC) number
        ---
        singular_value=null : float       # singular value corresponding to the PC
        motmask             : longblob    # PC (y, x)
        projection          : longblob    # projections onto the principle component (nframes)
        """

    class MovieSVD(dj.Part):
        """Components of the SVD from movie video.

        Attributes:
            master.Region (foreign key): Primary key of the FacialSignal.Region table.
            pc_no (int): principle component (PC) number.
            singular_value (float, optional): Singular value corresponding to the PC.
            movmask (longblob): PC (y, x)
            projection (longblob): Projections onto the principle component (nframes).
        """

        definition = """
        -> master.Region
        pc_no               : int         # principle component (PC) number
        ---
        singular_value=null : float       # singular value corresponding to the PC
        movmask             : longblob    # PC (y, x)
        projection          : longblob    # projections onto the principle component (nframes)
        """

    class Summary(dj.Part):
        """Average frames for movie and motion videos.

        Attributes:
            master (foreign key): Primary key from FacialSignal.
            sbin (int): Spatial bin size.
            avgframe (longblob): 2d np.array - average binned frame.
            avgmotion (longblob): 2d nd.array - average binned motion frame.
        """

        definition = """
        -> master
        ---
        sbin          : int         # spatial bin size
        avgframe      : longblob    # 2d np.array - average binned frame
        avgmotion     : longblob    # 2d nd.array - average binned motion frame
        """

    def make(self, key):
        """Populates the FacialSignal table by transferring the results from default
        Facemap outputs to the database."""

        dataset, _ = get_loader_result(key, FacemapTask)
        # Only motion SVD region type is supported.
        dataset["rois"] = [x for x in dataset["rois"] if x["rtype"] == "motion SVD"]

        self.insert1(key)

        self.Region.insert(
            [
                dict(
                    key,
                    roi_no=i,
                    xrange=dataset["rois"][i]["xrange"],
                    yrange=dataset["rois"][i]["yrange"],
                    xrange_bin=(
                        dataset["rois"][i]["xrange_bin"]
                        if "xrange_bin" in dataset["rois"][i]
                        else None
                    ),
                    yrange_bin=(
                        dataset["rois"][i]["yrange_bin"]
                        if "yrange_bin" in dataset["rois"][i]
                        else None
                    ),
                    motion=dataset["motion"][i + 1],
                )
                for i in range(len(dataset["rois"]))
                if dataset["rois"][i]["rtype"] == "motion SVD"
            ]
        )

        # MotionSVD
        if any(np.any(x) for x in dataset.get("motSVD", [False])):
            entry = [
                dict(
                    key,
                    roi_no=roi_no,
                    pc_no=i,
                    singular_value=(
                        dataset["motSv"][roi_no][i] if "motSv" in dataset else None
                    ),
                    motmask=dataset["motMask_reshape"][roi_no + 1][:, :, i],
                    projection=dataset["motSVD"][roi_no + 1][i],
                )
                for roi_no in range(len(dataset["rois"]))
                for i in range(dataset["motSVD"][roi_no + 1].shape[1])
            ]
            self.MotionSVD.insert(entry)

        # MovieSVD
        if any(np.any(x) for x in dataset.get("movSVD", [False])):
            entry = [
                dict(
                    key,
                    roi_no=roi_no,
                    pc_no=i,
                    singular_value=(
                        dataset["movSv"][roi_no][i] if "movSv" in dataset else None
                    ),
                    movmask=dataset["movMask_reshape"][roi_no + 1][:, :, i],
                    projection=dataset["movSVD"][roi_no + 1][i],
                )
                for roi_no in range(len(dataset["rois"]))
                for i in range(dataset["movSVD"][roi_no + 1].shape[1])
            ]
            self.MovieSVD.insert(entry)

        # Summary
        self.Summary.insert1(
            dict(
                key,
                sbin=dataset["sbin"],
                avgframe=dataset["avgframe"][0],
                avgmotion=dataset["avgmotion"][0],
            )
        )

Region

Bases: Part

Region's properties.

Attributes:

Name Type Description
master foreign key

Primary key of the FacialSignal table.

roi_no int

Region number.

roi_name str

User-friendly name of the roi.

xrange longblob

1d np.array - x pixel indices.

yrange longblob

1d np.array - y pixel indices.

xrange_bin longblob

1d np.array - binned x pixel indices.

yrange_bin longblob

1d np.array - binned y pixel indices.

motion longblob

1d np.array - absolute motion energies (nframes).

Source code in element_facemap/facial_behavior_estimation.py
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
class Region(dj.Part):
    """Region's properties.

    Attributes:
        master (foreign key): Primary key of the FacialSignal table.
        roi_no (int): Region number.
        roi_name (str, optional): User-friendly name of the roi.
        xrange (longblob): 1d np.array - x pixel indices.
        yrange (longblob): 1d np.array - y pixel indices.
        xrange_bin (longblob): 1d np.array - binned x pixel indices.
        yrange_bin (longblob): 1d np.array - binned y pixel indices.
        motion (longblob): 1d np.array - absolute motion energies (nframes).
    """

    definition = """
    -> master
    roi_no        : int         # Region number
    ---
    roi_name=''   : varchar(16) # user-friendly name of the roi
    xrange        : longblob    # 1d np.array - x pixel indices
    yrange        : longblob    # 1d np.array - y pixel indices
    xrange_bin    : longblob    # 1d np.array - binned x pixel indices
    yrange_bin    : longblob    # 1d np.array - binned y pixel indices
    motion        : longblob    # 1d np.array - absolute motion energies (nframes)
    """

MotionSVD

Bases: Part

Components of the SVD from motion video.

Attributes:

Name Type Description
master.Region foreign key

Primary key from FacialSignal.Region.

pc_no int

Principle component (PC) number.

singular_value float

singular value corresponding to the PC.

motmask longblob

PC (y, x).

projection longblob

projections onto the principle component (nframes).

Source code in element_facemap/facial_behavior_estimation.py
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
class MotionSVD(dj.Part):
    """Components of the SVD from motion video.

    Attributes:
        master.Region (foreign key): Primary key from FacialSignal.Region.
        pc_no (int): Principle component (PC) number.
        singular_value (float, optional): singular value corresponding to the PC.
        motmask (longblob): PC (y, x).
        projection (longblob): projections onto the principle component (nframes).
    """

    definition = """
    -> master.Region
    pc_no               : int         # principle component (PC) number
    ---
    singular_value=null : float       # singular value corresponding to the PC
    motmask             : longblob    # PC (y, x)
    projection          : longblob    # projections onto the principle component (nframes)
    """

MovieSVD

Bases: Part

Components of the SVD from movie video.

Attributes:

Name Type Description
master.Region foreign key

Primary key of the FacialSignal.Region table.

pc_no int

principle component (PC) number.

singular_value float

Singular value corresponding to the PC.

movmask longblob

PC (y, x)

projection longblob

Projections onto the principle component (nframes).

Source code in element_facemap/facial_behavior_estimation.py
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
class MovieSVD(dj.Part):
    """Components of the SVD from movie video.

    Attributes:
        master.Region (foreign key): Primary key of the FacialSignal.Region table.
        pc_no (int): principle component (PC) number.
        singular_value (float, optional): Singular value corresponding to the PC.
        movmask (longblob): PC (y, x)
        projection (longblob): Projections onto the principle component (nframes).
    """

    definition = """
    -> master.Region
    pc_no               : int         # principle component (PC) number
    ---
    singular_value=null : float       # singular value corresponding to the PC
    movmask             : longblob    # PC (y, x)
    projection          : longblob    # projections onto the principle component (nframes)
    """

Summary

Bases: Part

Average frames for movie and motion videos.

Attributes:

Name Type Description
master foreign key

Primary key from FacialSignal.

sbin int

Spatial bin size.

avgframe longblob

2d np.array - average binned frame.

avgmotion longblob

2d nd.array - average binned motion frame.

Source code in element_facemap/facial_behavior_estimation.py
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
class Summary(dj.Part):
    """Average frames for movie and motion videos.

    Attributes:
        master (foreign key): Primary key from FacialSignal.
        sbin (int): Spatial bin size.
        avgframe (longblob): 2d np.array - average binned frame.
        avgmotion (longblob): 2d nd.array - average binned motion frame.
    """

    definition = """
    -> master
    ---
    sbin          : int         # spatial bin size
    avgframe      : longblob    # 2d np.array - average binned frame
    avgmotion     : longblob    # 2d nd.array - average binned motion frame
    """

make(key)

Populates the FacialSignal table by transferring the results from default Facemap outputs to the database.

Source code in element_facemap/facial_behavior_estimation.py
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
def make(self, key):
    """Populates the FacialSignal table by transferring the results from default
    Facemap outputs to the database."""

    dataset, _ = get_loader_result(key, FacemapTask)
    # Only motion SVD region type is supported.
    dataset["rois"] = [x for x in dataset["rois"] if x["rtype"] == "motion SVD"]

    self.insert1(key)

    self.Region.insert(
        [
            dict(
                key,
                roi_no=i,
                xrange=dataset["rois"][i]["xrange"],
                yrange=dataset["rois"][i]["yrange"],
                xrange_bin=(
                    dataset["rois"][i]["xrange_bin"]
                    if "xrange_bin" in dataset["rois"][i]
                    else None
                ),
                yrange_bin=(
                    dataset["rois"][i]["yrange_bin"]
                    if "yrange_bin" in dataset["rois"][i]
                    else None
                ),
                motion=dataset["motion"][i + 1],
            )
            for i in range(len(dataset["rois"]))
            if dataset["rois"][i]["rtype"] == "motion SVD"
        ]
    )

    # MotionSVD
    if any(np.any(x) for x in dataset.get("motSVD", [False])):
        entry = [
            dict(
                key,
                roi_no=roi_no,
                pc_no=i,
                singular_value=(
                    dataset["motSv"][roi_no][i] if "motSv" in dataset else None
                ),
                motmask=dataset["motMask_reshape"][roi_no + 1][:, :, i],
                projection=dataset["motSVD"][roi_no + 1][i],
            )
            for roi_no in range(len(dataset["rois"]))
            for i in range(dataset["motSVD"][roi_no + 1].shape[1])
        ]
        self.MotionSVD.insert(entry)

    # MovieSVD
    if any(np.any(x) for x in dataset.get("movSVD", [False])):
        entry = [
            dict(
                key,
                roi_no=roi_no,
                pc_no=i,
                singular_value=(
                    dataset["movSv"][roi_no][i] if "movSv" in dataset else None
                ),
                movmask=dataset["movMask_reshape"][roi_no + 1][:, :, i],
                projection=dataset["movSVD"][roi_no + 1][i],
            )
            for roi_no in range(len(dataset["rois"]))
            for i in range(dataset["movSVD"][roi_no + 1].shape[1])
        ]
        self.MovieSVD.insert(entry)

    # Summary
    self.Summary.insert1(
        dict(
            key,
            sbin=dataset["sbin"],
            avgframe=dataset["avgframe"][0],
            avgmotion=dataset["avgmotion"][0],
        )
    )

get_loader_result(key, table)

Retrieve the facemap analysis results.

Parameters:

Name Type Description Default
key dict

A primary key for an entry in the provided table.

required
table Table

DataJoint user table from which loaded results are retrieved (i.e. FacemapTask).

required

Returns:

Name Type Description
loaded_dataset array

The results of the facemap analysis.

creation_time datetime

Date and time that the results files were created.

Source code in element_facemap/facial_behavior_estimation.py
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
def get_loader_result(
    key: dict, table: dj.user_tables.TableMeta
) -> Tuple[np.array, datetime]:
    """Retrieve the facemap analysis results.

    Args:
        key (dict): A primary key for an entry in the provided table.
        table (dj.Table): DataJoint user table from which loaded results are retrieved (i.e. FacemapTask).

    Returns:
        loaded_dataset (np.array): The results of the facemap analysis.
        creation_time (datetime): Date and time that the results files were created.
    """
    output_dir = (table & key).fetch1("facemap_output_dir")

    output_path = find_full_path(get_facemap_root_data_dir(), output_dir)
    output_file = glob(output_path.as_posix() + "/*_proc.npy")[0]

    loaded_dataset = np.load(output_file, allow_pickle=True).item()
    creation_time = datetime.fromtimestamp(Path(output_file).stat().st_ctime)

    return loaded_dataset, creation_time