别再对着CSV文件发愁了!手把手教你用Python把FER2013表情数据集转成图片
2026/4/24 20:16:33 网站建设 项目流程

从CSV到可视化:Python实战FER2013表情数据集预处理

第一次接触FER2013数据集的研究者往往会遇到一个令人困惑的场景——下载后的数据集不是常见的图片文件夹,而是一个结构复杂的CSV文件。这种数据格式对于刚入门深度学习的新手来说,确实是个不小的挑战。本文将带你一步步解析这个特殊的数据结构,并用Python将其转换为可直接用于模型训练的图片集。

1. 理解FER2013数据集的结构

FER2013是计算机视觉领域广泛使用的人脸表情识别基准数据集,包含35,886张48×48像素的灰度人脸图像,标注为7种基本表情类别。但与常见图像数据集不同,它采用了一种紧凑的CSV存储格式。

打开fer2013.csv文件,你会发现三列关键数据:

  • emotion:表情类别标签(0-6的整数值)
  • pixels:图像像素数据(以空格分隔的字符串)
  • Usage:数据用途标记(Training/PublicTest/PrivateTest)

7种表情对应的标签和含义如下表所示:

标签数字英文标签中文含义
0anger生气
1disgust厌恶
2fear恐惧
3happy开心
4sad伤心
5surprised惊讶
6neutral中性

注意:原始数据存在明显的类别不平衡问题,特别是"disgust"类样本数量仅为其他类别的1/10左右,这在后续模型训练时需要特别关注。

2. 环境准备与工具选择

在开始转换前,我们需要配置合适的Python环境。推荐使用Anaconda创建虚拟环境,避免包冲突:

conda create -n fer2013 python=3.8 conda activate fer2013

必需的核心库及其作用:

  • Pandas:高效读取和处理CSV数据
  • NumPy:数值计算和数组操作
  • OpenCV:图像处理和保存
  • Matplotlib(可选):图像可视化检查

安装命令:

pip install pandas numpy opencv-python matplotlib

对于深度学习后续应用,还需要准备:

pip install tensorflow keras

3. CSV到图像的完整转换流程

下面我们分步骤实现从CSV到图像文件夹的转换,每个表情类别会自动创建独立子目录。

3.1 数据加载与解析

首先创建一个Python脚本(如convert_fer2013.py),导入必要的库:

import os import pandas as pd import numpy as np import cv2 from tqdm import tqdm # 进度条显示

定义主转换函数:

def convert_fer2013(csv_path, output_dir="fer2013_images"): """ 将FER2013 CSV文件转换为分类图像文件夹 :param csv_path: fer2013.csv文件路径 :param output_dir: 输出目录名称 """ # 创建输出目录(如果不存在) os.makedirs(output_dir, exist_ok=True) # 读取CSV数据 df = pd.read_csv(csv_path) # 表情标签到名称的映射 emotion_map = { 0: "anger", 1: "disgust", 2: "fear", 3: "happy", 4: "sad", 5: "surprised", 6: "neutral" } # 遍历每一行数据 for idx, row in tqdm(df.iterrows(), total=len(df)): try: # 解析像素字符串 pixels = np.array([int(p) for p in row["pixels"].split()]) # 重塑为48x48图像 image = pixels.reshape(48, 48).astype(np.uint8) # 创建表情类别子目录 emotion_label = row["emotion"] emotion_name = emotion_map[emotion_label] emotion_dir = os.path.join(output_dir, emotion_name) os.makedirs(emotion_dir, exist_ok=True) # 生成唯一文件名 filename = f"{row['Usage']}_{idx}.jpg" filepath = os.path.join(emotion_dir, filename) # 保存图像 cv2.imwrite(filepath, image) except Exception as e: print(f"处理第{idx}行时出错: {str(e)}")

3.2 执行转换与验证

运行转换脚本:

if __name__ == "__main__": convert_fer2013("fer2013.csv") print("转换完成!")

转换完成后,检查输出目录结构应如下:

fer2013_images/ ├── anger/ ├── disgust/ ├── fear/ ├── happy/ ├── sad/ ├── surprised/ └── neutral/

为了验证转换结果,可以添加一个简单的可视化检查函数:

import matplotlib.pyplot as plt def visualize_samples(image_dir, samples_per_class=3): """ 从每个类别随机显示样本图像 """ emotions = os.listdir(image_dir) plt.figure(figsize=(15, 10)) for i, emotion in enumerate(emotions): emotion_path = os.path.join(image_dir, emotion) image_files = os.listdir(emotion_path)[:samples_per_class] for j, img_file in enumerate(image_files): img_path = os.path.join(emotion_path, img_file) img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) plt.subplot(len(emotions), samples_per_class, i*samples_per_class + j + 1) plt.imshow(img, cmap="gray") plt.title(emotion) plt.axis("off") plt.tight_layout() plt.show()

4. 高级处理与数据增强

得到图像文件后,我们还可以进行一些进阶处理,为后续的模型训练做好准备。

4.1 数据集统计分析

了解数据分布对于构建平衡的训练策略至关重要:

def analyze_distribution(image_dir): """ 分析各类别样本分布情况 """ emotion_counts = {} total = 0 for emotion in os.listdir(image_dir): emotion_path = os.path.join(image_dir, emotion) count = len(os.listdir(emotion_path)) emotion_counts[emotion] = count total += count # 打印统计信息 print(f"总样本数: {total}") for emotion, count in emotion_counts.items(): print(f"{emotion}: {count} ({count/total*100:.1f}%)") # 绘制分布图 plt.bar(emotion_counts.keys(), emotion_counts.values()) plt.title("FER2013数据集类别分布") plt.ylabel("样本数量") plt.xticks(rotation=45) plt.show()

4.2 数据增强策略

针对类别不平衡问题,可以使用Keras的ImageDataGenerator实现实时数据增强:

from tensorflow.keras.preprocessing.image import ImageDataGenerator def create_augmentor(): """ 创建数据增强生成器 """ return ImageDataGenerator( rotation_range=15, width_shift_range=0.1, height_shift_range=0.1, shear_range=0.1, zoom_range=0.1, horizontal_flip=True, fill_mode="nearest" )

4.3 高效数据加载方案

对于大型数据集,建议使用生成器方式加载数据,减少内存占用:

def image_generator(image_dir, batch_size=32, target_size=(48,48)): """ 创建高效图像数据生成器 """ datagen = ImageDataGenerator(rescale=1./255) generator = datagen.flow_from_directory( image_dir, target_size=target_size, color_mode="grayscale", batch_size=batch_size, class_mode="categorical" ) return generator

5. 常见问题与解决方案

在实际操作中,你可能会遇到以下典型问题:

5.1 路径相关问题

  • 问题表现FileNotFoundError或权限错误
  • 解决方案
    • 使用os.path模块处理路径,而非硬编码
    • 确保输出目录有写入权限
    • 在Windows系统中注意反斜杠转义
# 安全的路径拼接方式 output_dir = os.path.join("data", "fer2013")

5.2 像素值范围异常

  • 问题表现:保存的图像全黑或全白
  • 解决方案
    • 确保像素值在0-255范围内
    • 转换前检查数据范围:print(np.min(pixels), np.max(pixels))
    • 必要时进行归一化或反归一化

5.3 内存不足问题

  • 问题表现:处理大型CSV时内存溢出
  • 解决方案
    • 使用Pandas的chunksize参数分批读取
    • 考虑使用Dask等大数据处理库
# 分批读取大型CSV for chunk in pd.read_csv("large_fer2013.csv", chunksize=1000): process_chunk(chunk)

5.4 类别不平衡处理

针对FER2013中disgust类别样本少的问题:

  • 过采样少数类
  • 使用类别权重(class_weight)
  • 采用分层抽样确保训练/测试集分布一致
from sklearn.utils import class_weight # 计算类别权重 class_weights = class_weight.compute_class_weight( "balanced", classes=np.unique(train_labels), y=train_labels )

6. 完整代码整合

将所有功能整合到一个实用类中,方便复用:

import os import cv2 import numpy as np import pandas as pd from tqdm import tqdm from tensorflow.keras.preprocessing.image import ImageDataGenerator class FER2013Converter: """ FER2013数据集转换与处理工具类 """ EMOTION_MAP = { 0: "anger", 1: "disgust", 2: "fear", 3: "happy", 4: "sad", 5: "surprised", 6: "neutral" } def __init__(self, csv_path): self.csv_path = csv_path self.df = pd.read_csv(csv_path) def convert_to_images(self, output_dir, show_progress=True): """ 转换CSV到分类图像文件夹 """ os.makedirs(output_dir, exist_ok=True) iterator = tqdm(self.df.iterrows(), total=len(self.df)) if show_progress else self.df.iterrows() for idx, row in iterator: try: pixels = np.array([int(p) for p in row["pixels"].split()]) image = pixels.reshape(48, 48).astype(np.uint8) emotion_name = self.EMOTION_MAP[row["emotion"]] emotion_dir = os.path.join(output_dir, emotion_name) os.makedirs(emotion_dir, exist_ok=True) filename = f"{row['Usage']}_{idx}.jpg" cv2.imwrite(os.path.join(emotion_dir, filename), image) except Exception as e: print(f"Error processing row {idx}: {str(e)}") def get_class_distribution(self): """ 获取类别分布统计 """ return self.df["emotion"].value_counts().sort_index() @staticmethod def create_generator(image_dir, batch_size=32, augment=False): """ 创建数据生成器 """ if augment: datagen = ImageDataGenerator( rescale=1./255, rotation_range=15, width_shift_range=0.1, height_shift_range=0.1, shear_range=0.1, zoom_range=0.1, horizontal_flip=True, fill_mode="nearest" ) else: datagen = ImageDataGenerator(rescale=1./255) return datagen.flow_from_directory( image_dir, target_size=(48,48), color_mode="grayscale", batch_size=batch_size, class_mode="categorical" )

使用示例:

# 初始化转换器 converter = FER2013Converter("fer2013.csv") # 转换为图像 converter.convert_to_images("fer2013_images") # 创建数据生成器 train_generator = converter.create_generator("fer2013_images", augment=True)

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询