fsl-express / modules /data_cleaner.py
lasofeli's picture
Upload folder using huggingface_hub
bc971c7 verified
Raw
History Blame Contribute Delete
13.8 kB
import pandas as pd
import numpy as np
import torch
import json
from tqdm import tqdm
import os
import h5py
import csv
from os import listdir
from pathlib import Path
from modules.normalized_video_visualizer import normalize_megalist_frame
def fsl105_merge_metadata(root_dir, trim_indices):
final_dict = {}
with open(root_dir + "/labels.csv", mode="r") as infile:
with open(trim_indices, "r") as trimfile:
reader = csv.reader(infile)
trim_dict = json.load(trimfile)
next(reader)
for row in reader:
id_metadata = {"label": row[1], "category": row[2]}
final_dict.update({row[0]:id_metadata})
sign_video_list = listdir(root_dir + "/clips/" + row[0])
final_video_list = []
for x in sign_video_list:
video_instance = dict()
video_instance["filename"] = x
video_instance["filepath"] = root_dir + "/clips/" + str(row[0]) + "/" + x
remove = None
startsAt = None
endsAt = None
if row[0] in trim_dict:
if x in trim_dict[row[0]]:
remove = trim_dict[row[0]][x].get("remove")
startsAt = trim_dict[row[0]][x].get("start")
endsAt = trim_dict[row[0]][x].get("end")
video_instance["remove"] = remove
video_instance["startsAt"] = startsAt
video_instance["endsAt"] = endsAt
final_video_list.append(video_instance)
final_dict[row[0]].update({"instances":final_video_list})
with open("metadata/fsl105-labels.json", "w") as f:
f.write(json.dumps(final_dict, indent=2))
def get_valid_instances(filepath: str):
with open(filepath, "r") as file:
labels_dict = json.load(file)
for x in labels_dict.keys():
for y in labels_dict[x]["instances"]:
if y["remove"] != None:
labels_dict[x]["instances"].remove(y)
return labels_dict
def stream_npy_to_hdf5(source_dir, output_file):
source_path = Path(source_dir)
with h5py.File(output_file, "a") as hf:
class_dirs = [d for d in source_path.iterdir() if d.is_dir()]
for class_dir in class_dirs:
class_id = class_dir.name
grp = hf.require_group(class_id)
npy_files = list(class_dir.glob("*.npy"))
print(f"Processing class: {class_id} ({len(npy_files)} files)...")
for npy_path in npy_files:
file_name = npy_path.name
try:
features = np.load(npy_path)
arr = np.array(features, dtype="float32")
if file_name in grp:
del grp[file_name]
file_name = file_name.replace(".npy", "")
grp.create_dataset(file_name, data=arr, compression="gzip")
except Exception as e:
print(f"Error processing {npy_path}: {e}")
print(f"Final HDF5 file saved and closed at: {output_file}")
def process_and_save_normalized_hdf5(input_path, output_path):
if not os.path.exists(input_path):
print(f"Error: Source HDF5 not found at {input_path}")
return
with h5py.File(input_path, 'r') as source_hf, h5py.File(output_path, 'w') as target_hf:
for class_id in tqdm(source_hf.keys(), desc="Processing Classes"):
target_group = target_hf.create_group(class_id)
for file_key in source_hf[class_id].keys():
landmarks_raw = np.array(source_hf[class_id][file_key])[:, :, :2]
normalized_sequence = []
for frame_data in landmarks_raw:
b_norm, lh_norm, rh_norm = normalize_megalist_frame(frame_data)
combined_frame = torch.cat([b_norm, lh_norm, rh_norm], dim=0)
normalized_sequence.append(combined_frame.numpy())
final_data = np.array(normalized_sequence, dtype="float32")
target_group.create_dataset(
file_key,
data=final_data,
compression="gzip",
compression_opts=4
)
def flatten_samples_preserve_hierarchy(source_h5_path, target_h5_path, extraction_order):
mapping_logic = {}
for ds_name in ['pose', 'left_hand', 'right_hand', 'face']:
req = extraction_order[ds_name]
sorted_idx = sorted(list(set(req)))
idx_map = {idx: i for i, idx in enumerate(sorted_idx)}
reorder = np.array([idx_map[idx] for idx in req])
mapping_logic[ds_name] = {
'sorted': sorted_idx,
'reorder': reorder
}
with h5py.File(source_h5_path, 'r') as src, h5py.File(target_h5_path, 'w') as dst:
all_classes = list(src.keys())
for class_id in tqdm(all_classes, desc="Flattening Classes"):
class_group_dst = dst.create_group(class_id)
class_group_src = src[class_id]
for sample_name in class_group_src.keys():
sample_block = class_group_src[sample_name]
try:
parts = []
for ds_name in ['pose', 'left_hand', 'right_hand', 'face']:
logic = mapping_logic[ds_name]
data = sample_block[ds_name][:, logic['sorted'], :3]
data = data[:, logic['reorder'], :]
parts.append(data)
combined_tensor = np.concatenate(parts, axis=1).astype(np.float32)
class_group_dst.create_dataset(
sample_name,
data=combined_tensor,
compression="gzip",
chunks=True
)
except Exception as e:
print(f"Error processing {class_id}/{sample_name}: {e}")
print(f"\nProcessing complete. New hierarchy saved to: {target_h5_path}")
def apply_signbart_normalization(data):
pose_len = len(extraction_order['pose'])
lh_len = len(extraction_order['left_hand'])
rh_len = len(extraction_order['right_hand'])
part_indices = {
"body": (0, pose_len),
"lh": (pose_len, pose_len + lh_len),
"rh": (pose_len + lh_len, pose_len + lh_len + rh_len)
}
normalized = data.copy()
for name, (start, end) in part_indices.items():
part_data = normalized[:, start:end, :2]
mask = (part_data != 0).any(axis=-1)
if not np.any(mask):
continue
points = part_data[mask]
p_min = points.min(axis=0)
p_max = points.max(axis=0)
margin = (p_max - p_min) * 0.05
p_min -= margin
p_max += margin
range_val = p_max - p_min
range_val[range_val == 0] = 1.0
normalized[:, start:end, :2] = np.where(
normalized[:, start:end, :2] != 0,
(normalized[:, start:end, :2] - p_min) / range_val,
0
)
return normalized
def extract_video_data(pose_seq, face_seq, lh_seq, rh_seq, extraction_order):
def get_ordered_indices(indices, sequence):
requested_indices = extraction_order[indices]
sorted_indices = sorted(list(set(requested_indices)))
data_subset = sequence[:, sorted_indices, :]
index_map = {idx: i for i, idx in enumerate(sorted_indices)}
reorder_map = [index_map[idx] for idx in requested_indices]
return data_subset[:, reorder_map, :]
pose = get_ordered_indices("pose", pose_seq)[:, :, :2]
lh = get_ordered_indices("left_hand", lh_seq)[:, :, :2]
rh = get_ordered_indices("right_hand", rh_seq)[:, :, :2]
face = get_ordered_indices("face", face_seq)[:, :, :2]
combined = np.concatenate([pose, lh, rh, face], axis=1)
return combined
def flatten_samples_preserve_hierarchy(source_h5_path, target_h5_path, extraction_order):
mapping_logic = {}
for ds_name in ['pose', 'left_hand', 'right_hand', 'face']:
req = extraction_order[ds_name]
sorted_idx = sorted(list(set(req)))
idx_map = {idx: i for i, idx in enumerate(sorted_idx)}
reorder = np.array([idx_map[idx] for idx in req])
mapping_logic[ds_name] = {
'sorted': sorted_idx,
'reorder': reorder
}
with h5py.File(source_h5_path, 'r') as src, h5py.File(target_h5_path, 'w') as dst:
all_classes = list(src.keys())
for class_id in tqdm(all_classes, desc="Flattening Classes"):
class_group_dst = dst.create_group(class_id)
class_group_src = src[class_id]
for sample_name in class_group_src.keys():
sample_block = class_group_src[sample_name]
try:
parts = []
for ds_name in ['pose', 'left_hand', 'right_hand', 'face']:
logic = mapping_logic[ds_name]
data = sample_block[ds_name][:, logic['sorted'], :3]
data = data[:, logic['reorder'], :]
parts.append(data)
combined_tensor = np.concatenate(parts, axis=1).astype(np.float32)
class_group_dst.create_dataset(
sample_name,
data=combined_tensor,
compression="gzip",
chunks=True
)
except Exception as e:
print(f"Error processing {class_id}/{sample_name}: {e}")
print(f"\nProcessing complete. New hierarchy saved to: {target_h5_path}")
def apply_hybrid_normalization(data, extraction_order):
pose_len = len(extraction_order['pose'])
lh_len = len(extraction_order['left_hand'])
rh_len = len(extraction_order['right_hand'])
pose_start = 0
lh_start = pose_len
rh_start = lh_start + lh_len
face_start = rh_start + rh_len
FACE_REGIONS = {
"left_eye": [46, 52, 53, 65, 7, 159, 155, 145, 70, 107, 105, 22, 23, 24, 110, 157, 158],
"right_eye": [295, 283, 282, 276, 382, 386, 249, 374, 336, 300, 285, 252, 253, 254, 339, 384, 385],
"mouth": [324, 13, 78, 14, 61, 291, 37, 0, 267, 84, 17, 314, 308, 318, 402, 312, 178, 88, 95]
}
region_map = {}
for name, ids in FACE_REGIONS.items():
indices = [face_start + extraction_order['face'].index(lm_id)
for lm_id in ids if lm_id in extraction_order['face']]
region_map[name] = indices
normalized = data.copy()
for f in range(normalized.shape[0]):
frame = normalized[f]
try:
NOSE_I = pose_start + extraction_order['pose'].index(0)
L_SHOULDER_I = pose_start + extraction_order['pose'].index(11)
R_SHOULDER_I = pose_start + extraction_order['pose'].index(12)
L_EYE_I = face_start + extraction_order['face'].index(386)
shoulder_dist = np.linalg.norm(frame[L_SHOULDER_I, :2] - frame[R_SHOULDER_I, :2])
head_unit = shoulder_dist / 2.0
if head_unit > 1e-8:
nose_x = frame[NOSE_I, 0]
l_eye_y = frame[L_EYE_I, 1]
box_left = nose_x - (3 * head_unit)
box_right = nose_x + (3 * head_unit)
box_top = l_eye_y + (0.5 * head_unit)
box_bottom = l_eye_y - (6 * head_unit)
width = max(box_right - box_left, 1e-8)
height = max(box_top - box_bottom, 1e-8)
pose_indices = range(pose_start, lh_start)
for idx in pose_indices:
if not np.all(frame[idx, :2] == 0):
frame[idx, 0] = (frame[idx, 0] - box_left) / width - 0.5
frame[idx, 1] = (frame[idx, 1] - box_bottom) / height - 0.5
except ValueError:
pass
for start, end in [(lh_start, rh_start), (rh_start, face_start)]:
pts = frame[start:end, :2]
mask = (pts != 0).any(axis=-1)
if np.sum(mask) >= 2:
h_min, h_max = pts[mask].min(axis=0), pts[mask].max(axis=0)
side = np.max(h_max - h_min) * 1.2
if side > 1e-8:
center = (h_min + h_max) / 2.0
box_min = center - (side / 2.0)
frame[start:end, :2] = np.where(
frame[start:end, :2] != 0,
((frame[start:end, :2] - box_min) / side) - 0.5,
0
)
for region_name, indices in region_map.items():
pts = frame[indices, :2]
mask = (pts != 0).any(axis=-1)
if np.sum(mask) >= 2:
p_min, p_max = pts[mask].min(axis=0), pts[mask].max(axis=0)
side = np.max(p_max - p_min) * 1.2
if side > 1e-8:
center = (p_min + p_max) / 2.0
box_min = center - (side / 2.0)
frame[indices, :2] = np.where(
frame[indices, :2] != 0,
((frame[indices, :2] - box_min) / side) - 0.5,
0
)
normalized[f] = frame
return normalized