如何在同一图表中为同帧多面孔绘制不同颜色的情感变化折线图?
解决方案
要实现单帧多人脸的分折线绘制,核心是给每张人脸分配唯一标识,再按标识分组绘制。以下是具体步骤和代码:
1. 给人脸添加唯一ID
如果你的人脸识别系统没有输出跟踪ID,可通过人脸框(bbox)的IOU匹配生成跨帧的统一ID(确保同一人脸在不同帧用同一个ID):
# 先按帧排序数据 df = df.sort_values('Frame').reset_index(drop=True) # 初始化FaceID列 df['FaceID'] = -1 current_id = 0 prev_faces = {} # 存储上一帧的人脸框与对应ID for frame in df['Frame'].unique(): current_frame = df[df['Frame'] == frame].copy() if frame == df['Frame'].min(): # 第一帧直接分配ID current_frame['FaceID'] = range(current_id, current_id + len(current_frame)) current_id += len(current_frame) # 记录第一帧的人脸框 for idx, row in current_frame.iterrows(): prev_faces[row['FaceID']] = (row['x1'], row['y1'], row['x2'], row['y2']) else: current_faces = [] for idx, row in current_frame.iterrows(): bbox = (row['x1'], row['y1'], row['x2'], row['y2']) max_iou = 0 matched_id = -1 # 计算当前人脸与上一帧所有人脸的IOU,匹配同一人脸 for face_id, prev_bbox in prev_faces.items(): x1_inter = max(bbox[0], prev_bbox[0]) y1_inter = max(bbox[1], prev_bbox[1]) x2_inter = min(bbox[2], prev_bbox[2]) y2_inter = min(bbox[3], prev_bbox[3]) inter_area = max(0, x2_inter - x1_inter) * max(0, y2_inter - y1_inter) bbox_area = (bbox[2] - bbox[0]) * (bbox[3] - bbox[1]) prev_area = (prev_bbox[2] - prev_bbox[0]) * (prev_bbox[3] - prev_bbox[1]) iou = inter_area / (bbox_area + prev_area - inter_area) if iou > max_iou and iou > 0.5: # 0.5为IOU匹配阈值,可调整 max_iou = iou matched_id = face_id if matched_id != -1: current_faces.append(matched_id) prev_faces[matched_id] = bbox else: # 新出现的人脸分配新ID current_faces.append(current_id) prev_faces[current_id] = bbox current_id += 1 current_frame['FaceID'] = current_faces # 更新原DataFrame的FaceID df.loc[df['Frame'] == frame, 'FaceID'] = current_frame['FaceID']
如果没有人脸框数据,可临时用帧内编号区分(但跨帧同一人脸会被识别为不同ID):
df['FaceID'] = df.groupby('Frame').cumcount()
2. 绘制情绪随帧变化的分人脸折线图
import matplotlib.pyplot as plt # 定义情绪与数值的映射 emotion_map = {'Angry': 0, 'Fear': 1, 'Happy': 2, 'Neutral': 3, 'Sad': 4} df['Emotion_Code'] = df['Emotion'].map(emotion_map) plt.figure(figsize=(20,5)) # 按FaceID分组绘制折线 for face_id, group in df.groupby('FaceID'): # 确保按帧顺序排序 sorted_group = group.sort_values('Frame') plt.plot(sorted_group['Frame'], sorted_group['Emotion_Code'], label=f'人脸 {face_id}') # 设置y轴刻度与标签 plt.gca().set_yticks(list(emotion_map.values())) plt.gca().set_yticklabels(list(emotion_map.keys())) plt.title("各人脸情绪随帧变化") plt.xlabel("帧编号") plt.ylabel("情绪") plt.tick_params(labelsize=10) # 图例放在右侧避免遮挡 plt.legend(title='人脸ID', bbox_to_anchor=(1.05, 1), loc='upper left') plt.tight_layout() plt.show()
3. 年龄、性别绘制的类似方法
年龄折线图
plt.figure(figsize=(20,5)) for face_id, group in df.groupby('FaceID'): sorted_group = group.sort_values('Frame') plt.plot(sorted_group['Frame'], sorted_group['Age'], label=f'人脸 {face_id}') plt.title("各人脸年龄随帧变化") plt.xlabel("帧编号") plt.ylabel("年龄") plt.tick_params(labelsize=10) plt.legend(title='人脸ID', bbox_to_anchor=(1.05, 1), loc='upper left') plt.tight_layout() plt.show()
性别折线图
gender_map = {'Male': 0, 'Female': 1} df['Gender_Code'] = df['Gender'].map(gender_map) plt.figure(figsize=(20,5)) for face_id, group in df.groupby('FaceID'): sorted_group = group.sort_values('Frame') plt.plot(sorted_group['Frame'], sorted_group['Gender_Code'], label=f'人脸 {face_id}') plt.gca().set_yticks(list(gender_map.values())) plt.gca().set_yticklabels(list(gender_map.keys())) plt.title("各人脸性别随帧变化") plt.xlabel("帧编号") plt.ylabel("性别") plt.tick_params(labelsize=10) plt.legend(title='人脸ID', bbox_to_anchor=(1.05, 1), loc='upper left') plt.tight_layout() plt.show()
内容的提问来源于stack exchange,提问作者Vidarshana Dissanayaka
相关产品推荐
相关产品推荐

