用Python处理IMDB-WIKI人脸数据集:从.mat文件解析到年龄计算实战
用Python解析IMDB-WIKI人脸数据集从.mat文件到年龄计算的完整指南当你第一次下载IMDB-WIKI数据集时面对那些神秘的.mat文件可能会感到无从下手。作为包含超过50万张名人面部图像的数据集它不仅是年龄估计研究的黄金标准也是人脸识别项目的重要资源。本文将带你一步步解析这个数据集从加载.mat文件到最终计算出每张图片对应的真实年龄。1. 理解IMDB-WIKI数据集结构IMDB-WIKI数据集由两个主要来源组成IMDb互联网电影数据库和Wikipedia。数据集中的每张图像都附带有丰富的元数据这些数据存储在.mat格式的文件中。让我们先看看这些.mat文件包含哪些关键字段dob出生日期Matlab序列号格式photo_taken照片拍摄年份full_path图像文件相对路径gender性别编码0女性1男性NaN未知name名人姓名face_location面部位置坐标用于裁剪face_score面部检测分数越高表示检测越可靠second_face_score第二张脸的检测分数用于过滤多人图像注意数据集中的年龄信息是通过计算出生日期和照片拍摄日期之间的差值得到的这被称为真实年龄actual age与外貌年龄apparent age不同。2. 加载和解析.mat文件Python的scipy.io模块可以轻松加载.mat文件无需安装MATLAB。以下是加载和初步解析.mat文件的完整代码import scipy.io as sio import numpy as np from datetime import datetime def load_mat_file(mat_path): 加载IMDB-WIKI的.mat文件并返回结构化数据 mat_data sio.loadmat(mat_path) # 提取主要数据结构 data_struct mat_data[imdb][0, 0] # 创建字段名到索引的映射 fields { dob: 0, photo_taken: 1, full_path: 2, gender: 3, name: 4, face_location: 5, face_score: 6, second_face_score: 7 } return data_struct, fields加载后我们可以检查数据结构的内容mat_path imdb/imdb.mat # 替换为你的实际路径 data, fields load_mat_file(mat_path) # 打印第一个样本的信息 print(出生日期:, data[fields[dob]][0][0]) print(拍摄年份:, data[fields[photo_taken]][0][0]) print(姓名:, data[fields[name]][0][0][0]) print(性别:, data[fields[gender]][0][0]) print(面部位置:, data[fields[face_location]][0][0])3. 计算真实年龄.mat文件中的日期存储为MATLAB序列号我们需要将其转换为Python日期对象才能计算年龄。以下是完整的年龄计算函数def matlab_datenum_to_python(matlab_datenum): 将MATLAB日期序列号转换为Python datetime对象 python_datenum datetime.fromordinal(int(matlab_datenum)) \ timedelta(daysfloat(matlab_datenum)%1) - \ timedelta(days366) return python_datenum def calculate_age(dob_matlab, photo_year): 计算真实年龄 # 转换出生日期 dob matlab_datenum_to_python(dob_matlab) # 假设照片拍摄于年中7月1日 photo_date datetime(photo_year, 7, 1) # 计算年龄 age photo_date.year - dob.year if (photo_date.month, photo_date.day) (dob.month, dob.day): age - 1 return age现在我们可以批量计算所有样本的年龄ages [] for dob, photo_year in zip(data[fields[dob]][0], data[fields[photo_taken]][0]): age calculate_age(dob, photo_year) ages.append(age) print(前10个样本的年龄:, ages[:10])4. 数据清洗和质量控制IMDB-WIKI数据集虽然庞大但包含一些需要过滤的低质量样本。以下是关键的质量控制步骤过滤低质量面部检测quality_mask np.array([score 3.0 for score in data[fields[face_score]][0]])排除多人图像single_face_mask np.array([np.isnan(score) or score 0 for score in data[fields[second_face_score]][0]])有效性别过滤valid_gender_mask ~np.isnan(data[fields[gender]][0])组合所有过滤条件final_mask quality_mask single_face_mask valid_gender_mask filtered_data {field: data[fields[field]][0][final_mask] for field in fields} filtered_ages np.array(ages)[final_mask]提示face_score阈值设为3.0是基于经验值你可以根据具体需求调整这个阈值。5. 可视化数据集统计信息了解数据集的分布特征对后续建模至关重要。以下是使用matplotlib绘制年龄和性别分布的代码import matplotlib.pyplot as plt plt.figure(figsize(12, 5)) # 年龄分布 plt.subplot(1, 2, 1) plt.hist(filtered_ages, bins50, colorskyblue) plt.title(年龄分布) plt.xlabel(年龄) plt.ylabel(样本数) # 性别分布 plt.subplot(1, 2, 2) gender_counts np.bincount(filtered_data[gender].astype(int)) plt.bar([女性, 男性], gender_counts, color[pink, lightblue]) plt.title(性别分布) plt.ylabel(样本数) plt.tight_layout() plt.show()6. 提取和保存面部图像根据face_location字段我们可以从原始图像中裁剪出面部区域。以下是完整的图像处理流程import os from PIL import Image def crop_and_save_faces(data_dict, base_image_dir, output_dir): 根据face_location裁剪并保存面部图像 os.makedirs(output_dir, exist_okTrue) for i, (path, location) in enumerate(zip(data_dict[full_path], data_dict[face_location])): img_path os.path.join(base_image_dir, path[0]) try: img Image.open(img_path) # 转换坐标格式 [x1, y1, x2, y2] x1, y1, x2, y2 map(int, location[0]) face img.crop((x1, y1, x2, y2)) # 保存裁剪后的图像 output_path os.path.join(output_dir, fface_{i}.jpg) face.save(output_path) except Exception as e: print(f处理 {img_path} 时出错: {str(e)})7. 构建完整的数据处理管道将上述步骤整合为一个完整的数据处理类class IMDBWikiProcessor: def __init__(self, mat_path, image_dir): self.mat_path mat_path self.image_dir image_dir self.data None self.fields None self.ages None def load_and_process(self): 加载并处理.mat文件 self.data, self.fields load_mat_file(self.mat_path) self.ages [calculate_age(dob, year) for dob, year in zip(self.data[self.fields[dob]][0], self.data[self.fields[photo_taken]][0])] def filter_data(self, min_face_score3.0): 应用质量控制过滤 quality_mask np.array([score min_face_score for score in self.data[self.fields[face_score]][0]]) single_face_mask np.array([np.isnan(score) or score 0 for score in self.data[self.fields[second_face_score]][0]]) valid_gender_mask ~np.isnan(self.data[self.fields[gender]][0]) final_mask quality_mask single_face_mask valid_gender_mask filtered_data { full_path: self.data[self.fields[full_path]][0][final_mask], face_location: self.data[self.fields[face_location]][0][final_mask], gender: self.data[self.fields[gender]][0][final_mask], age: np.array(self.ages)[final_mask] } return filtered_data使用这个类可以简化整个处理流程processor IMDBWikiProcessor(imdb/imdb.mat, imdb/images) processor.load_and_process() clean_data processor.filter_data() # 保存处理后的数据 np.savez(processed_imdb.npz, **clean_data)在实际项目中处理IMDB-WIKI数据集时最耗时的部分往往是面部图像的裁剪和保存。为了提高效率可以考虑使用多进程处理特别是当数据集规模很大时。