beatsync-video-model / inference_preprocess.py
TanishkOrion's picture
uofaso
0c0fa10
Raw
History Blame Contribute Delete
13.8 kB
# import numpy as np
# import cv2
# from skimage.util import img_as_float
# import tensorflow as tf
# import matplotlib.pyplot as plt
# import time
# import scipy.io
# from scipy.sparse import spdiags
# def preprocess_raw_video(videoFilePath, dim=36):
# #########################################################################
# # set up
# t = []
# i = 0
# vidObj = cv2.VideoCapture(videoFilePath);
# totalFrames = int(vidObj.get(cv2.CAP_PROP_FRAME_COUNT)) # get total frame size
# Xsub = np.zeros((totalFrames, dim, dim, 3), dtype = np.float32)
# height = vidObj.get(cv2.CAP_PROP_FRAME_HEIGHT)
# width = vidObj.get(cv2.CAP_PROP_FRAME_WIDTH)
# success, img = vidObj.read()
# dims = img.shape
# print("Orignal Height", height)
# print("Original width", width)
# #########################################################################
# # Crop each frame size into dim x dim
# while success:
# t.append(vidObj.get(cv2.CAP_PROP_POS_MSEC))# current timestamp in milisecond
# vidLxL = cv2.resize(img_as_float(img[:, int(width/2)-int(height/2 + 1):int(height/2)+int(width/2), :]), (dim, dim), interpolation = cv2.INTER_AREA)
# vidLxL = cv2.rotate(vidLxL, cv2.ROTATE_90_CLOCKWISE) # rotate 90 degree
# vidLxL = cv2.cvtColor(vidLxL.astype('float32'), cv2.COLOR_BGR2RGB)
# vidLxL[vidLxL > 1] = 1
# vidLxL[vidLxL < (1/255)] = 1/255
# Xsub[i, :, :, :] = vidLxL
# success, img = vidObj.read() # read the next one
# i = i + 1
# plt.imshow(Xsub[0])
# plt.title('Sample Preprocessed Frame')
# plt.show()
# #########################################################################
# # Normalized Frames in the motion branch
# normalized_len = len(t) - 1
# dXsub = np.zeros((normalized_len, dim, dim, 3), dtype = np.float32)
# for j in range(normalized_len - 1):
# dXsub[j, :, :, :] = (Xsub[j+1, :, :, :] - Xsub[j, :, :, :]) / (Xsub[j+1, :, :, :] + Xsub[j, :, :, :])
# dXsub = dXsub / np.std(dXsub)
# #########################################################################
# # Normalize raw frames in the apperance branch
# Xsub = Xsub - np.mean(Xsub)
# Xsub = Xsub / np.std(Xsub)
# Xsub = Xsub[:totalFrames-1, :, :, :]
# #########################################################################
# # Plot an example of data after preprocess
# dXsub = np.concatenate((dXsub, Xsub), axis = 3);
# return dXsub
# def detrend(signal, Lambda):
# """detrend(signal, Lambda) -> filtered_signal
# This function applies a detrending filter.
# This code is based on the following article "An advanced detrending method with application
# to HRV analysis". Tarvainen et al., IEEE Trans on Biomedical Engineering, 2002.
# *Parameters*
# ``signal`` (1d numpy array):
# The signal where you want to remove the trend.
# ``Lambda`` (int):
# The smoothing parameter.
# *Returns*
# ``filtered_signal`` (1d numpy array):
# The detrended signal.
# """
# signal_length = signal.shape[0]
# # observation matrix
# H = np.identity(signal_length)
# # second-order difference matrix
# ones = np.ones(signal_length)
# minus_twos = -2 * np.ones(signal_length)
# diags_data = np.array([ones, minus_twos, ones])
# diags_index = np.array([0, 1, 2])
# D = spdiags(diags_data, diags_index, (signal_length - 2), signal_length).toarray()
# filtered_signal = np.dot((H - np.linalg.inv(H + (Lambda ** 2) * np.dot(D.T, D))), signal)
# return filtered_signal
# import numpy as np
# import cv2
# import mediapipe as mp
# from scipy.sparse import spdiags
# import logging
# # Set up a logger
# logger = logging.getLogger(__name__)
# def detrend(signal, Lambda):
# """Applies a detrending filter to a signal."""
# signal_length = signal.shape[0]
# H = np.identity(signal_length)
# ones = np.ones(signal_length)
# minus_twos = -2 * np.ones(signal_length)
# diags_data = np.array([ones, minus_twos, ones])
# diags_index = np.array([0, 1, 2])
# D = spdiags(diags_data, diags_index, (signal_length - 2), signal_length).toarray()
# filtered_signal = np.dot((H - np.linalg.inv(H + (Lambda ** 2) * np.dot(D.T, D))), signal)
# return filtered_signal
# def preprocess_raw_video(video_path, dim=36):
# """
# Preprocesses a video to extract the forehead region using MediaPipe.
# This version completely replaces the need for dlib.
# """
# # --- 1. SETUP MEDIAPIPE ---
# mp_face_mesh = mp.solutions.face_mesh
# face_mesh = mp_face_mesh.FaceMesh(
# static_image_mode=False,
# max_num_faces=1,
# min_detection_confidence=0.5
# )
# # --- 2. VIDEO CAPTURE SETUP ---
# vidObj = cv2.VideoCapture(video_path)
# if not vidObj.isOpened():
# raise IOError(f"Cannot open video file: {video_path}")
# total_frames = int(vidObj.get(cv2.CAP_PROP_FRAME_COUNT))
# logger.info(f"Total frames in video: {total_frames}")
# # --- 3. FRAME-BY-FRAME PROCESSING ---
# all_forehead_rois = []
# frames_processed = 0
# while True:
# success, frame = vidObj.read()
# if not success:
# break
# frames_processed += 1
# # Convert the BGR image to RGB.
# rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# # Process the frame and find face landmarks.
# results = face_mesh.process(rgb_frame)
# if results.multi_face_landmarks:
# # Assume only one face.
# face_landmarks = results.multi_face_landmarks[0]
# # --- 4. EXTRACT FOREHEAD REGION ---
# # Using specific MediaPipe landmark indices for the forehead
# # Index 10 is roughly the top of the nose bridge.
# # We will create a bounding box above this point.
# # Get landmark coordinates (normalized 0-1, so we multiply by frame dimensions)
# h, w, _ = frame.shape
# # We'll define the forehead ROI based on a few key points.
# # A common approach is to use points on the eyebrows and above.
# # E.g., Landmark 105 (right), 334 (left), 10 (center-ish top)
# p1 = face_landmarks.landmark[105]
# p2 = face_landmarks.landmark[334]
# p_top = face_landmarks.landmark[10]
# x1 = int(p1.x * w)
# y1 = int(p1.y * h)
# x2 = int(p2.x * w)
# y2 = int(p_top.y * h)
# # Add some padding to get a good region
# padding_y = 15
# padding_x = 10
# y_start = max(0, y2 - padding_y)
# y_end = min(h, y1 + padding_y)
# x_start = min(x1, x2) - padding_x
# x_end = max(x1, x2) + padding_x
# # Crop the forehead
# forehead_roi = frame[y_start:y_end, x_start:x_end]
# if forehead_roi.size > 0:
# # Resize to the dimension required by the model (36x36)
# resized_roi = cv2.resize(forehead_roi, (dim, dim), interpolation=cv2.INTER_AREA)
# all_forehead_rois.append(resized_roi)
# vidObj.release()
# face_mesh.close()
# if not all_forehead_rois:
# raise ValueError("Could not detect a face or forehead in any frame of the video.")
# logger.info(f"Successfully extracted forehead ROI from {len(all_forehead_rois)} frames.")
# # --- 5. POST-PROCESSING FOR THE MODEL ---
# Xsub = np.array(all_forehead_rois, dtype=np.float32) / 255.0
# # Calculate motion stream (temporal difference)
# dXsub = np.diff(Xsub, axis=0)
# dXsub = np.concatenate((dXsub, np.zeros((1, dim, dim, 3), dtype=np.float32)), axis=0)
# dXsub = (dXsub - np.mean(dXsub)) / np.std(dXsub)
# # Normalize appearance stream
# Xsub = (Xsub - np.mean(Xsub)) / np.std(Xsub)
# # Combine motion and appearance streams as expected by the model
# # Note: The original code seems to expect 6 channels, but the model input shapes
# # suggest two separate inputs of 3 channels each. We will create the 6-channel
# # array as per the original preprocessing logic.
# dXsub = np.concatenate((dXsub, Xsub), axis=3)
# return dXsub
# import cv2
# import numpy as np
# import mediapipe as mp
# from skimage.transform import resize
# import logging
# # Set up a logger
# logger = logging.getLogger(__name__)
# def preprocess_video_for_inference(video_path, target_size=(36, 36)):
# """
# Preprocesses a video by detecting and cropping faces using MediaPipe,
# then calculates the normalized motion differences for model inference.
# This is a direct replacement for the previous dlib-based approach.
# """
# # --- 1. SETUP MEDIAPIPE ---
# # Use the lightweight and efficient Face Detection model
# mp_face_detection = mp.solutions.face_detection
# face_detection = mp_face_detection.FaceDetection(model_selection=0, min_detection_confidence=0.5)
# # --- 2. VIDEO CAPTURE AND SETUP ---
# cap = cv2.VideoCapture(video_path)
# if not cap.isOpened():
# raise ValueError(f"Error: Could not open video file: {video_path}")
# cropped_frames = []
# total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
# logger.info(f"Total frames to process: {total_frames}")
# # --- 3. FRAME-BY-FRAME PROCESSING ---
# while cap.isOpened():
# ret, frame = cap.read()
# if not ret:
# break
# # Convert the BGR image to RGB for MediaPipe
# rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# # Process the frame to detect faces
# results = face_detection.process(rgb_frame)
# if results.detections:
# # Get the bounding box of the first detected face
# detection = results.detections[0]
# bboxC = detection.location_data.relative_bounding_box
# ih, iw, _ = frame.shape
# # Calculate absolute coordinates
# x, y, w, h = int(bboxC.xmin * iw), int(bboxC.ymin * ih), \
# int(bboxC.width * iw), int(bboxC.height * ih)
# # Ensure coordinates are valid
# x, y, w, h = max(0, x), max(0, y), max(0, w), max(0, h)
# face = frame[y:y+h, x:x+w]
# if face.size > 0:
# # Resize face to the target dimension (e.g., 36x36)
# resized_face = resize(face, target_size, anti_aliasing=True)
# # Append all three color channels
# cropped_frames.append(resized_face)
# cap.release()
# face_detection.close()
# if not cropped_frames:
# raise ValueError("Could not detect a face in any frame of the video.")
# logger.info(f"Successfully extracted face crops from {len(cropped_frames)} frames.")
# # --- 4. CORE POST-PROCESSING LOGIC (UNCHANGED) ---
# Xsub = np.array(cropped_frames, dtype=np.float32)
# # Normalize Appearance Stream
# Xsub = (Xsub - np.mean(Xsub)) / np.std(Xsub)
# # Calculate Motion Stream (Temporal Difference)
# dXsub = np.diff(Xsub, axis=0)
# # Pad the last frame to maintain original length
# dXsub = np.concatenate((dXsub, np.zeros((1, target_size[0], target_size[1], 3), dtype=np.float32)), axis=0)
# # Normalize Motion Stream
# dXsub = (dXsub - np.mean(dXsub)) / np.std(dXsub)
# # Combine streams into a 6-channel array as required by the model
# final_input = np.concatenate((dXsub, Xsub), axis=3)
# return final_input
import cv2
import numpy as np
import mediapipe as mp
from skimage.transform import resize
import logging
logger = logging.getLogger(__name__)
def preprocess_video_for_inference(video_path, target_size=(36, 36)):
mp_face_detection = mp.solutions.face_detection
face_detection = mp_face_detection.FaceDetection(model_selection=0, min_detection_confidence=0.5)
cap = cv2.VideoCapture(video_path)
if not cap.isOpened():
raise ValueError(f"Error: Could not open video file: {video_path}")
cropped_frames = []
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
results = face_detection.process(rgb_frame)
if results.detections:
detection = results.detections[0]
bboxC = detection.location_data.relative_bounding_box
ih, iw, _ = frame.shape
x, y, w, h = int(bboxC.xmin * iw), int(bboxC.ymin * ih), \
int(bboxC.width * iw), int(bboxC.height * ih)
x, y, w, h = max(0, x), max(0, y), max(0, w), max(0, h)
face = frame[y:y+h, x:x+w]
if face.size > 0:
resized_face = resize(face, target_size, anti_aliasing=True)
cropped_frames.append(resized_face)
cap.release()
face_detection.close()
if not cropped_frames:
raise ValueError("Could not detect a face in any frame of the video.")
Xsub = np.array(cropped_frames, dtype=np.float32)
Xsub = (Xsub - np.mean(Xsub)) / np.std(Xsub)
dXsub = np.diff(Xsub, axis=0)
dXsub = np.concatenate((dXsub, np.zeros((1, target_size[0], target_size[1], 3), dtype=np.float32)), axis=0)
dXsub = (dXsub - np.mean(dXsub)) / np.std(dXsub)
final_input = np.concatenate((dXsub, Xsub), axis=3)
return final_input