1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 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 154 155 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 221 222 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
| 将CASME II视频序列和标注文件转换为YOLOv8格式
要将CASME II数据集转换为YOLOv8可用的格式,我们需要完成以下几个关键步骤:从视频中提取帧、处理标注信息、转换为YOLO格式的标注文件,并组织成正确的目录结构。
## 1. 准备工作
### 1.1 安装必要库 ```bash pip install opencv-python pandas numpy tqdm ```
### 1.2 目录结构准备 ``` CASME2_YOLO/ ├── images/ │ ├── train/ │ └── val/ └── labels/ ├── train/ └── val/ ```
## 2. 完整转换脚本
```python import os import cv2 import pandas as pd import numpy as np from tqdm import tqdm from sklearn.model_selection import train_test_split
def convert_casme2_to_yolo(casme_root, output_dir, test_size=0.2): """ 将CASME II数据集转换为YOLOv8格式 参数: casme_root: CASME II数据集根目录 output_dir: 输出目录 test_size: 验证集比例 """ # 创建输出目录 os.makedirs(os.path.join(output_dir, "images", "train"), exist_ok=True) os.makedirs(os.path.join(output_dir, "images", "val"), exist_ok=True) os.makedirs(os.path.join(output_dir, "labels", "train"), exist_ok=True) os.makedirs(os.path.join(output_dir, "labels", "val"), exist_ok=True)
# 读取标注文件 annotation_path = os.path.join(casme_root, "CASME2-coding-20190701.xlsx") df = pd.read_excel(annotation_path) # 微表情类别映射 emotion_map = { 'happiness': 0, 'surprise': 1, 'disgust': 2, 'repression': 3, 'others': 4 } # 收集所有样本用于后续分割 all_samples = [] for idx, row in tqdm(df.iterrows(), total=len(df), desc="Processing videos"): subject = row['Subject'] video_name = row['Filename'] onset = row['OnsetFrame'] apex = row['ApexFrame'] offset = row['OffsetFrame'] emotion = row['Estimated Emotion'] # 处理视频文件 video_path = os.path.join(casme_root, "RAW", f"sub{subject:02}", video_name) cap = cv2.VideoCapture(video_path) if not cap.isOpened(): print(f"Warning: Could not open video {video_path}") continue # 获取视频总帧数 total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # 读取每一帧 for frame_num in range(total_frames): ret, frame = cap.read() if not ret: break # 只处理微表情区间内的帧 if onset <= frame_num + 1 <= offset: # CASME II帧号从1开始 # 生成唯一文件名 base_name = f"sub{subject:02}_{video_name.split('.')[0]}_{frame_num+1:04d}" # 保存图像 img_path = os.path.join(output_dir, "images", "train", f"{base_name}.jpg") cv2.imwrite(img_path, frame) # 创建YOLO格式的标注文件 label_path = os.path.join(output_dir, "labels", "train", f"{base_name}.txt") # 这里需要添加面部检测和微表情区域标注的逻辑 # 由于CASME II不提供bbox标注,我们需要自己生成或使用面部检测 # 伪代码 - 实际应用中需要替换为真实的面部检测和微表情区域定位 height, width = frame.shape[:2] # 假设我们检测到面部并定位微表情区域 # 这里使用简单居中矩形作为示例 (实际应用需要替换) x_center = 0.5 y_center = 0.4 bbox_width = 0.3 bbox_height = 0.2 # 写入YOLO格式标注 with open(label_path, 'w') as f: f.write(f"{emotion_map.get(emotion.lower(), 4)} {x_center} {y_center} {bbox_width} {bbox_height}\n") # 添加到样本列表 all_samples.append((img_path, label_path, emotion)) cap.release() # 分割训练集和验证集 if len(all_samples) > 0: train_samples, val_samples = train_test_split( all_samples, test_size=test_size, random_state=42, stratify=[s[2] for s in all_samples] ) # 移动验证集文件 for img_path, label_path, _ in val_samples: new_img_path = img_path.replace("/train/", "/val/") new_label_path = label_path.replace("/train/", "/val/") os.rename(img_path, new_img_path) os.rename(label_path, new_label_path) # 创建dataset.yaml文件 yaml_content = f"""path: {os.path.abspath(output_dir)} train: images/train val: images/val
# 类别 names: 0: happiness 1: surprise 2: disgust 3: repression 4: others """ with open(os.path.join(output_dir, "casme2.yaml"), 'w') as f: f.write(yaml_content) print("转换完成!")
# 使用示例 if __name__ == "__main__": convert_casme2_to_yolo( casme_root="/path/to/CASME2", # 替换为你的CASME II路径 output_dir="CASME2_YOLO" ) ```
## 3. 关键问题解决方案
### 3.1 缺少边界框标注的问题 CASME II数据集不提供面部或微表情区域的边界框标注,解决方法有:
1. **使用面部检测器自动生成边界框**: ```python # 使用OpenCV的DNN面部检测器 def detect_face(frame): net = cv2.dnn.readNetFromCaffe( "deploy.prototxt", # 从OpenCV或网上获取 "res10_300x300_ssd_iter_140000.caffemodel" # 预训练权重 ) h, w = frame.shape[:2] blob = cv2.dnn.blobFromImage(cv2.resize(frame, (300, 300)), 1.0, (300, 300), (104.0, 177.0, 123.0)) net.setInput(blob) detections = net.forward() for i in range(detections.shape[2]): confidence = detections[0, 0, i, 2] if confidence > 0.5: # 置信度阈值 box = detections[0, 0, i, 3:7] * np.array([w, h, w, h]) return box # 返回(x1, y1, x2, y2) return None # 如果没有检测到面部 ```
2. **使用面部Landmark定位微表情区域**: ```python # 使用dlib或MediaPipe获取面部关键点 # 然后根据关键点定义ROI区域 ```
### 3.2 时间维度处理 微表情是时序现象,可以考虑:
1. **使用连续多帧作为输入**: ```python # 在转换脚本中保存连续帧序列 frame_sequence = [] sequence_length = 5 # 使用5帧序列
# 在处理视频时保存序列 if len(frame_sequence) < sequence_length: frame_sequence.append(frame) else: frame_sequence.pop(0) frame_sequence.append(frame) # 保存序列中的中间帧作为代表帧 # 并标注整个序列的微表情 ```
2. **生成光流图作为额外通道**: ```python def compute_optical_flow(prev_frame, current_frame): prev_gray = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY) curr_gray = cv2.cvtColor(current_frame, cv2.COLOR_BGR2GRAY) flow = cv2.calcOpticalFlowFarneback( prev_gray, curr_gray, None, 0.5, 3, 15, 3, 5, 1.2, 0 ) # 将光流转换为RGB可视化 hsv = np.zeros_like(prev_frame) hsv[..., 1] = 255 mag, ang = cv2.cartToPolar(flow[..., 0], flow[..., 1]) hsv[..., 0] = ang * 180 / np.pi / 2 hsv[..., 2] = cv2.normalize(mag, None, 0, 255, cv2.NORM_MINMAX) return cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR) ```
## 4. 使用转换后的数据训练YOLOv8
```python from ultralytics import YOLO
# 加载模型 model = YOLO('yolov8n.pt') # 或 yolov8s, yolov8m 等
# 使用转换后的数据训练 results = model.train( data='CASME2_YOLO/casme2.yaml', imgsz=640, epochs=100, batch=16, patience=20, device='0', # 使用GPU project='microexpression_detection', name='yolov8n_casme2' ) ```
## 5. 注意事项
1. **数据量问题**:CASME II样本较少,建议使用数据增强或与其他微表情数据集合并 2. **类别不平衡**:某些微表情类别样本较少,训练时可使用加权损失 3. **评估指标**:微表情检测需要特殊评估指标,不能仅依赖常规目标检测指标 4. **时序信息**:考虑结合LSTM或3D CNN处理时序信息
通过以上方法,你可以将CASME II数据集成功转换为YOLOv8可用的格式,并训练一个微表情检测模型。实际应用中可能需要根据具体需求调整边界框生成策略和模型架构。
|