OpenCV Python中cv2.train函数空训练数据报错求助
解决OpenCV EigenFaceRecognizer训练时“空训练数据”错误
错误信息
error: (-5:Bad argument) Empty training data was given. You'll need more than one sample to learn a model. in function 'train'.
问题分析
这个错误说明training_images或training_labels为空,或仅包含单个样本/类别,导致模型无法完成训练。结合你的.pgm图片和代码逻辑,核心原因集中在:
- 训练数据路径配置错误,未读取到任何图片
- 图片读取逻辑存在漏洞,所有.pgm文件被跳过
- 目录结构不符合代码预期,未正确遍历到子目录中的图片
解决步骤
1. 修正训练数据路径
你的代码中注释了正确路径,但实际使用的是错误路径,直接修改为正确路径:
# 替换原错误路径 path_to_training_images = '/home/ace/OpenCV/cascades/'
确保目录结构符合要求:每个子目录对应一个人脸类别,子目录下存放该类别的.pgm图片,示例结构:
cascades/ ├── Alice/ │ ├── face1.pgm │ ├── face2.pgm ├── Bob/ │ ├── face1.pgm │ ├── face2.pgm
2. 调试图片读取过程
在read_images函数中添加调试输出,确认图片是否被成功读取:
def read_images(path, image_size): names = [] training_images, training_labels = [], [] label = 0 for dirname, subdirnames, filenames in os.walk(path): for subdirname in subdirnames: names.append(subdirname) subject_path = os.path.join(dirname, subdirname) print(f"读取类别: {subdirname},路径: {subject_path}") file_count = 0 for filename in os.listdir(subject_path): img_path = os.path.join(subject_path, filename) print(f"尝试读取文件: {img_path}") img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) if img is None: print(f"读取失败,跳过该文件") continue file_count += 1 img = cv2.resize(img, image_size) training_images.append(img) training_labels.append(label) print(f"该类别成功读取 {file_count} 张图片") label += 1 training_images = np.asarray(training_images, np.uint8) training_labels = np.asarray(training_labels, np.int32) print(f"总计读取 {len(training_images)} 张训练图片") return names, training_images, training_labels
运行后查看输出,若所有.pgm文件读取失败,需检查文件是否损坏,或尝试转换为.png格式测试。
3. 优化训练数据读取逻辑
原代码的遍历逻辑依赖严格的目录结构,改用更鲁棒的方式,直接识别所有.pgm文件并按目录分类:
def read_images(path, image_size): names = [] training_images, training_labels = [], [] label_map = {} current_label = 0 # 遍历所有文件,仅处理.pgm格式 for root, _, files in os.walk(path): for file in files: if not file.lower().endswith('.pgm'): continue # 获取当前文件所属类别(目录名) class_name = os.path.basename(root) # 为新类别分配标签 if class_name not in label_map: label_map[class_name] = current_label names.append(class_name) current_label += 1 # 读取并处理图片 img_path = os.path.join(root, file) img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) if img is None: continue img = cv2.resize(img, image_size) training_images.append(img) training_labels.append(label_map[class_name]) training_images = np.asarray(training_images, np.uint8) training_labels = np.asarray(training_labels, np.int32) return names, training_images, training_labels
4. 训练前添加数据校验
在调用model.train前,先检查数据是否符合训练要求:
names, training_images, training_labels = read_images(path_to_training_images, training_image_size) # 检查训练数据是否为空 if len(training_images) == 0: raise ValueError("未读取到任何训练图片,请检查路径和文件") # 检查是否至少包含两个类别 if len(np.unique(training_labels)) < 2: raise ValueError("训练数据仅含一个类别,模型需至少两个类别才能训练") model = cv2.face.EigenFaceRecognizer_create() model.train(training_images, training_labels)
修改后的完整代码
import os import cv2 import numpy as np def read_images(path, image_size): names = [] training_images, training_labels = [], [] label_map = {} current_label = 0 # 遍历所有文件,仅处理.pgm格式 for root, _, files in os.walk(path): for file in files: if not file.lower().endswith('.pgm'): continue # 获取当前文件所属类别(目录名) class_name = os.path.basename(root) # 为新类别分配标签 if class_name not in label_map: label_map[class_name] = current_label names.append(class_name) current_label += 1 # 读取并处理图片 img_path = os.path.join(root, file) img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) if img is None: continue img = cv2.resize(img, image_size) training_images.append(img) training_labels.append(label_map[class_name]) training_images = np.asarray(training_images, np.uint8) training_labels = np.asarray(training_labels, np.int32) return names, training_images, training_labels path_to_training_images = '/home/ace/OpenCV/cascades/' training_image_size = (200, 200) names, training_images, training_labels = read_images(path_to_training_images, training_image_size) # 数据校验 if len(training_images) == 0: raise ValueError("未读取到任何训练图片,请检查路径和文件") if len(np.unique(training_labels)) < 2: raise ValueError("训练数据仅含一个类别,模型需至少两个类别才能训练") model = cv2.face.EigenFaceRecognizer_create() model.train(training_images, training_labels) face_cascade = cv2.CascadeClassifier('/haarcascade_frontalface_default.xml') camera = cv2.VideoCapture(2) while (cv2.waitKey(1) == -1): success, frame = camera.read() if success: faces = face_cascade.detectMultiScale(frame, 1.3, 5) for (x, y, w, h) in faces: cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2) gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) roi_gray = gray[x:x+w, y:y+h] if roi_gray.size == 0: continue roi_gray = cv2.resize(roi_gray, training_image_size) label, confidence = model.predict(roi_gray) text = '%s, confidence=%.2f' % (names[label], confidence) cv2.putText(frame, text, (x, y - 20), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2) cv2.imshow('Face Recognition', frame)
内容的提问来源于stack exchange,提问作者Jr Cord
相关产品推荐
相关产品推荐

