facial tremor testing
This commit is contained in:
@@ -7,7 +7,7 @@ created: 2020-20-07
|
|||||||
from dbm_lib.dbm_features.raw_features.audio import intensity, pitch_freq, hnr, gne, voice_frame_score, formant_freq
|
from dbm_lib.dbm_features.raw_features.audio import intensity, pitch_freq, hnr, gne, voice_frame_score, formant_freq
|
||||||
from dbm_lib.dbm_features.raw_features.audio import pause_segment, jitter, shimmer, mfcc
|
from dbm_lib.dbm_features.raw_features.audio import pause_segment, jitter, shimmer, mfcc
|
||||||
from dbm_lib.dbm_features.raw_features.video import face_asymmetry, face_au, face_emotion_expressivity, face_landmark
|
from dbm_lib.dbm_features.raw_features.video import face_asymmetry, face_au, face_emotion_expressivity, face_landmark
|
||||||
from dbm_lib.dbm_features.raw_features.movement import head_motion, eye_blink, voice_tremor
|
from dbm_lib.dbm_features.raw_features.movement import head_motion, eye_blink, voice_tremor, facial_tremor
|
||||||
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import logging
|
import logging
|
||||||
@@ -82,9 +82,6 @@ def process_acoustic(video_uri, out_dir, dbm_group, r_config):
|
|||||||
logger.info('processing mfcc....')
|
logger.info('processing mfcc....')
|
||||||
mfcc.run_mfcc(video_uri, out_dir, r_config)
|
mfcc.run_mfcc(video_uri, out_dir, r_config)
|
||||||
|
|
||||||
logger.info('processing voice tremor....')
|
|
||||||
voice_tremor.run_vtremor(video_uri, out_dir, r_config)
|
|
||||||
|
|
||||||
def process_facial(video_uri, out_dir, dbm_group, r_config):
|
def process_facial(video_uri, out_dir, dbm_group, r_config):
|
||||||
"""
|
"""
|
||||||
processing facial features
|
processing facial features
|
||||||
@@ -120,6 +117,7 @@ def process_movement(video_uri, out_dir, dbm_group, r_config, dlib_model):
|
|||||||
return
|
return
|
||||||
|
|
||||||
logger.info('Processing movement variables from data in {}'.format(video_uri))
|
logger.info('Processing movement variables from data in {}'.format(video_uri))
|
||||||
|
|
||||||
logger.info('processing head movement....')
|
logger.info('processing head movement....')
|
||||||
head_motion.run_head_movement(video_uri, out_dir, r_config)
|
head_motion.run_head_movement(video_uri, out_dir, r_config)
|
||||||
|
|
||||||
@@ -129,6 +127,9 @@ def process_movement(video_uri, out_dir, dbm_group, r_config, dlib_model):
|
|||||||
logger.info('processing voice tremor....')
|
logger.info('processing voice tremor....')
|
||||||
voice_tremor.run_vtremor(video_uri, out_dir, r_config)
|
voice_tremor.run_vtremor(video_uri, out_dir, r_config)
|
||||||
|
|
||||||
|
logger.info('processing facial tremor....')
|
||||||
|
face_tremor.fac_tremor_process(video_uri, out_dir, r_config, model_output=True)
|
||||||
|
|
||||||
def remove_file(file_path):
|
def remove_file(file_path):
|
||||||
"""
|
"""
|
||||||
removing wav file
|
removing wav file
|
||||||
|
|||||||
@@ -13,3 +13,4 @@ import os
|
|||||||
DBMLIB_PATH = os.path.dirname(__file__)
|
DBMLIB_PATH = os.path.dirname(__file__)
|
||||||
DBMLIB_VTREMOR_LIB = os.path.abspath(os.path.join(DBMLIB_PATH,
|
DBMLIB_VTREMOR_LIB = os.path.abspath(os.path.join(DBMLIB_PATH,
|
||||||
'../../../../resources/libraries/voice_tremor.praat'))
|
'../../../../resources/libraries/voice_tremor.praat'))
|
||||||
|
DBMLIB_FTREMOR_CONFIG = os.path.abspath(os.path.join(DBMLIB_PATH, '../resources/features/facial/config.json'))
|
||||||
|
|||||||
159
dbm_lib/dbm_features/raw_features/movement/facial_tremor.py
Normal file
159
dbm_lib/dbm_features/raw_features/movement/facial_tremor.py
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
import sys, os, glob, cv2, re
|
||||||
|
import pickle, json
|
||||||
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
|
import numpy.ma as ma
|
||||||
|
import logging
|
||||||
|
from os.path import join
|
||||||
|
|
||||||
|
from dbm_lib.dbm_features.raw_features.util import util as ut
|
||||||
|
from dbm_lib.dbm_features.raw_features.util.math_util import *
|
||||||
|
|
||||||
|
from dbm_lib.dbm_features.raw_features.movement import DBMLIB_FTREMOR_CONFIG
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
logger=logging.getLogger()
|
||||||
|
|
||||||
|
ft_dir = 'movement/facial_tremor'
|
||||||
|
csv_ext = '_fac_tremor.csv'
|
||||||
|
model_ext = '_fac_model.csv'
|
||||||
|
fac_features_ext = '_fac_features.csv'
|
||||||
|
|
||||||
|
def compute_features(out_dir, df_of, r_config):
|
||||||
|
""" Computes features
|
||||||
|
|
||||||
|
Returns: features in vector format
|
||||||
|
"""
|
||||||
|
config = json.loads(open(DBMLIB_FTREMOR_CONFIG,'r').read())
|
||||||
|
logger.info('json file read')
|
||||||
|
pattern_x = re.compile("l\d+_x")
|
||||||
|
pattern_y = re.compile("l\d+_y")
|
||||||
|
|
||||||
|
# assumption: distance of face to camera remains at roughly static
|
||||||
|
|
||||||
|
# logic break
|
||||||
|
landmark_columns = []
|
||||||
|
for col in df_of.columns:
|
||||||
|
if pattern_x.match(col) or pattern_y.match(col):
|
||||||
|
landmark_columns.append(col)
|
||||||
|
|
||||||
|
df_of= df_of[(df_of[landmark_columns]!= 0).any(axis=1)]
|
||||||
|
df_of.reset_index(inplace=True)
|
||||||
|
|
||||||
|
num_frames = len(df)
|
||||||
|
logger.info("Number of frames to be processed: {}".format(str(num_frames)))
|
||||||
|
landmarks = config['landmarks']
|
||||||
|
|
||||||
|
try:
|
||||||
|
if num_frames == 0:
|
||||||
|
error_reason = "No frames with visible face."
|
||||||
|
logger.error(error_reason)
|
||||||
|
return empty_frame(landmarks, r_config, error_reason)
|
||||||
|
|
||||||
|
# if num_frames < 60:
|
||||||
|
# error_reason = 'Number of frames with visible face < 60. Video too short'
|
||||||
|
# logger.error(error_reason)
|
||||||
|
# return empty_frame(landmarks, f_cfg, error_reason)
|
||||||
|
|
||||||
|
first_row = df_of.iloc[0]
|
||||||
|
|
||||||
|
facew = abs(first_row[config['face_width_left']] - first_row[config['face_width_right']])
|
||||||
|
faceh = abs(first_row[config['face_height_left']] - first_row[config['face_height_right']])
|
||||||
|
|
||||||
|
if facew == 0 or faceh == 0:
|
||||||
|
error_reason = 'face width or height = 0. Check landmark values'
|
||||||
|
logger.error(error_reason)
|
||||||
|
return empty_frame(landmarks, r_config)
|
||||||
|
|
||||||
|
fac_disp = calc_displacement_vec(df_of, landmarks, num_frames)
|
||||||
|
|
||||||
|
# if verbose:
|
||||||
|
# logger.info("Displacement output: {}".format(str(fac_disp)))
|
||||||
|
|
||||||
|
fac_disp_median = np.median(fac_disp, axis = 1)
|
||||||
|
fac_disp_mean = np.mean(fac_disp, axis = 1)
|
||||||
|
|
||||||
|
if len(fac_disp.shape)!=2:
|
||||||
|
error_reason = 'fac_disp is not 2D. smth went wrong with disp calc'
|
||||||
|
logger.error(error_reason)
|
||||||
|
return empty_frame(landmarks, r_config, error_reason)
|
||||||
|
|
||||||
|
if len(fac_disp[0])<=1:
|
||||||
|
error_reason = 'Video too short. smth went wrong with disp calc'
|
||||||
|
logger.error(error_reason)
|
||||||
|
return empty_frame(landmarks, r_config, error_reason)
|
||||||
|
|
||||||
|
fac_corr_mat = np.corrcoef(fac_disp, rowvar = True)
|
||||||
|
# extract relevant row from cov matrix
|
||||||
|
ref_lmk_index = [i for i, lmk in enumerate(landmarks) if config['ref_lmk']==lmk]
|
||||||
|
fac_corr = fac_corr_mat[ref_lmk_index][0]
|
||||||
|
|
||||||
|
fac_area = config['ref_area'] / (facew * faceh)
|
||||||
|
|
||||||
|
# if verbose:
|
||||||
|
# logger.info("Face area: {}".format(fac_area))
|
||||||
|
# logger.info("Face Displacement Median: {}".format(str(fac_disp_median)))
|
||||||
|
# logger.info("Face Displacement Mean: {}".format(str(fac_disp_mean)))
|
||||||
|
|
||||||
|
fac_features1 = np.multiply(fac_area * fac_disp_median, (1. - fac_corr))
|
||||||
|
fac_features2 = np.multiply(fac_area * fac_disp_mean, (1. - fac_corr))
|
||||||
|
|
||||||
|
# base_fac_features = np.dot(fac_area * fac_disp_median, (1. - fac_corr))
|
||||||
|
|
||||||
|
fac_features_dict = {}
|
||||||
|
for i, landmark in enumerate(landmarks):
|
||||||
|
fac_features_dict['fac_features_mean_{}'.format(landmark)] = [fac_features2[i]]
|
||||||
|
raw_variable_map = 'fac_tremor_median_{}'.format(landmark)
|
||||||
|
fac_features_dict[r_config.raw_feature[raw_variable_map]] = [fac_features1[i]]
|
||||||
|
|
||||||
|
fac_features_dict['fac_disp_median_{}'.format(landmark)] = [fac_disp_median[i]]
|
||||||
|
fac_features_dict['fac_corr_{}'.format(landmark)] = [fac_corr[i]]
|
||||||
|
|
||||||
|
fac_features_dict[r_config.err_reason] = ['']
|
||||||
|
data = pd.DataFrame.from_dict(fac_features_dict)
|
||||||
|
logger.info('Concluded computing tremor features')
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error('Error computing tremor features: {}'.format(str(e)))
|
||||||
|
return empty_frame(landmarks, r_config, str(e))
|
||||||
|
|
||||||
|
def empty_frame(landmarks, r_config, error_reason):
|
||||||
|
fac_features_dict = {}
|
||||||
|
for i, landmark in enumerate(landmarks):
|
||||||
|
raw_variable_map = 'fac_tremor_median_{}'.format(landmark)
|
||||||
|
fac_features_dict[r_config.raw_feature[raw_variable_map]] = [np.nan]
|
||||||
|
|
||||||
|
fac_features_dict['fac_features_mean_{}'.format(landmark)] = [np.nan]
|
||||||
|
fac_features_dict['fac_disp_median_{}'.format(landmark)] = [np.nan]
|
||||||
|
fac_features_dict['fac_corr_{}'.format(landmark)] = [np.nan]
|
||||||
|
|
||||||
|
fac_features_dict[r_config.err_reason] = [error_reason]
|
||||||
|
empty_frame = pd.DataFrame.from_dict(fac_features_dict)
|
||||||
|
return empty_frame
|
||||||
|
|
||||||
|
def fac_tremor_process(video_uri,out_dir,r_config, model_output=False):
|
||||||
|
"""
|
||||||
|
processing input videos
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
logger.info('filtering path: ',video_uri,out_dir)
|
||||||
|
input_loc, out_loc, fl_name = ut.filter_path(video_uri, out_dir)
|
||||||
|
of_csv_path = glob.glob(join(out_loc, fl_name + '_OF_video_features/*.csv'))
|
||||||
|
|
||||||
|
if len(of_csv_path)>0:
|
||||||
|
of_csv = of_csv_path[0]
|
||||||
|
df_of = pd.read_csv(of_csv, error_bad_lines=False)
|
||||||
|
|
||||||
|
logger.info('Processing Output file {} '.format(os.path.join(out_loc, fl_name)))
|
||||||
|
|
||||||
|
feats = compute_features(of_csv_path , df_of, r_config)
|
||||||
|
if model_output:
|
||||||
|
result = score(feats, r_config)
|
||||||
|
feats = pd.concat([feats, result], axis=1)
|
||||||
|
|
||||||
|
ut.output_audio_feature(feats, new_out_base_dir, '/'+fac_dir, fac_ext)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error('Failed to process video file')
|
||||||
@@ -15,9 +15,9 @@ from dbm_lib.dbm_features.raw_features.util import util as ut
|
|||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
logger=logging.getLogger()
|
logger=logging.getLogger()
|
||||||
|
|
||||||
def batch_open_face(filepaths,video_url, input_dir, out_dir, of_path):
|
def batch_open_face(filepaths,video_url, input_dir, out_dir, of_path,video_tracking=False):
|
||||||
""" Computes open_face features for the files in filepaths
|
""" Computes open_face features for the files in filepaths
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
-----
|
-----
|
||||||
filepaths: (itreable[str])
|
filepaths: (itreable[str])
|
||||||
@@ -27,46 +27,49 @@ def batch_open_face(filepaths,video_url, input_dir, out_dir, of_path):
|
|||||||
input_dir: Path to the input videos
|
input_dir: Path to the input videos
|
||||||
out_dir: Path to the processed output
|
out_dir: Path to the processed output
|
||||||
of_path: OpenFace source code path
|
of_path: OpenFace source code path
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
--------
|
--------
|
||||||
(itreable[str]) list of .csv files
|
(itreable[str]) list of .csv files
|
||||||
"""
|
"""
|
||||||
|
if video_tracking:
|
||||||
suffix = '_OF_features'
|
suffix = '_OF_video_features/'
|
||||||
|
else:
|
||||||
|
suffix = '_OF_features'
|
||||||
|
|
||||||
csv_files = []
|
csv_files = []
|
||||||
|
|
||||||
for fp in filepaths:
|
for fp in filepaths:
|
||||||
try:
|
try:
|
||||||
|
|
||||||
_, out_loc, fl_name = ut.filter_path(video_url, out_dir)
|
_, out_loc, fl_name = ut.filter_path(video_url, out_dir)
|
||||||
full_f_name = fl_name + suffix
|
full_f_name = fl_name + suffix
|
||||||
output_directory = os.path.join(out_loc, full_f_name)
|
output_directory = os.path.join(out_loc, full_f_name)
|
||||||
|
|
||||||
csv_files.append(ut.compute_open_face_features(fp,output_directory,of_path))
|
csv_files.append(ut.compute_open_face_features(fp,output_directory,of_path))
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error('Failed to run OpenFace on {}\n{}'.format(fp, e))
|
logger.error('Failed to run OpenFace on {}\n{}'.format(fp, e))
|
||||||
|
|
||||||
return csv_files
|
return csv_files
|
||||||
|
|
||||||
def process_open_face(video_uri, input_dir, out_dir, of_path, dbm_group):
|
def process_open_face(video_uri, input_dir, out_dir, of_path, dbm_group,video_tracking):
|
||||||
"""
|
"""
|
||||||
Processing all patient's for fetching emotion expressivity
|
Processing all patient's for fetching emotion expressivity
|
||||||
-------------------
|
-------------------
|
||||||
-------------------
|
-------------------
|
||||||
Args:
|
Args:
|
||||||
video_uri: video path; input_dir : input directory for video's; dbm_group: feature group
|
video_uri: video path; input_dir : input directory for video's; dbm_group: feature group
|
||||||
out_dir: (str) Output directory for processed output; of_path: OpenFace source code path
|
out_dir: (str) Output directory for processed output; of_path: OpenFace source code path
|
||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
|
||||||
if dbm_group != None and len(dbm_group) == 1 and 'acoustic' in dbm_group:
|
if dbm_group != None and len(dbm_group) == 1 and 'acoustic' in dbm_group:
|
||||||
return
|
return
|
||||||
|
|
||||||
filepaths = [video_uri]
|
filepaths = [video_uri]
|
||||||
csv_filepaths = batch_open_face(filepaths, video_uri, input_dir, out_dir, of_path)
|
csv_filepaths = batch_open_face(filepaths, video_uri, input_dir, out_dir, of_path,video_tracking)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error('Failed to process video file')
|
logger.error('Failed to process video file')
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ import time
|
|||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
logger=logging.getLogger()
|
logger=logging.getLogger()
|
||||||
|
|
||||||
|
#for ftremor
|
||||||
|
OPENFACE_PATH_VIDEO = '/pkg/OpenFace/build/bin/FaceLandmarkVid'
|
||||||
OPENFACE_PATH = 'pkg/OpenFace/build/bin/FeatureExtraction'
|
OPENFACE_PATH = 'pkg/OpenFace/build/bin/FeatureExtraction'
|
||||||
DLIB_SHAPE_MODEL = 'pkg/shape_detector/shape_predictor_68_face_landmarks.dat'
|
DLIB_SHAPE_MODEL = 'pkg/shape_detector/shape_predictor_68_face_landmarks.dat'
|
||||||
|
|
||||||
@@ -35,6 +37,7 @@ def common_video(video_file, args, r_config):
|
|||||||
of.process_open_face(video_file, os.path.dirname(video_file), out_path, OPENFACE_PATH, args.dbm_group)
|
of.process_open_face(video_file, os.path.dirname(video_file), out_path, OPENFACE_PATH, args.dbm_group)
|
||||||
pf.process_facial(video_file, out_path, args.dbm_group, r_config)
|
pf.process_facial(video_file, out_path, args.dbm_group, r_config)
|
||||||
pf.process_acoustic(video_file, out_path, args.dbm_group, r_config)
|
pf.process_acoustic(video_file, out_path, args.dbm_group, r_config)
|
||||||
|
of.process_open_face(video_file, os.path.dirname(video_file), out_path, OPENFACE_PATH_VIDEO, args.dbm_group,video_tracking=True)
|
||||||
pf.process_movement(video_file, out_path, args.dbm_group, r_config, DLIB_SHAPE_MODEL)
|
pf.process_movement(video_file, out_path, args.dbm_group, r_config, DLIB_SHAPE_MODEL)
|
||||||
pf.remove_file(video_file)
|
pf.remove_file(video_file)
|
||||||
|
|
||||||
|
|||||||
1
resources/features/facial/config.json
Normal file
1
resources/features/facial/config.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"ref_lmk": 28, "ref_area": 350000, "face_width_left": "l15_x", "face_width_right": "l1_x", "face_height_left": "l8_y", "face_height_right": "l27_y", "landmarks": [5, 12, 8, 48, 54, 28, 51, 66, 57], "model_path": "resources/facial/svm_bin_fac_tremor.sav", "feature_order": ["fac_features_mean_5", "fac_features_mean_12", "fac_features_mean_8", "fac_features_mean_48", "fac_features_mean_54", "fac_features_mean_28", "fac_features_mean_51", "fac_features_mean_66", "fac_features_mean_57", "fac_features_median_5", "fac_features_median_12", "fac_features_median_8", "fac_features_median_48", "fac_features_median_54", "fac_features_median_28", "fac_features_median_51", "fac_features_median_66", "fac_features_median_57"]}
|
||||||
Reference in New Issue
Block a user